|
Blender
V2.59
|
00001 /* 00002 * $Id: poselib.c 36924 2011-05-26 13:38:16Z 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) 2007, Blender Foundation 00021 * This is a new part of Blender 00022 * 00023 * Contributor(s): Joshua Leung 00024 * 00025 * ***** END GPL LICENSE BLOCK ***** 00026 */ 00027 00033 #include <stdlib.h> 00034 #include <stdio.h> 00035 #include <stddef.h> 00036 #include <string.h> 00037 #include <math.h> 00038 #include <float.h> 00039 00040 #include "MEM_guardedalloc.h" 00041 00042 #include "BLI_math.h" 00043 #include "BLI_blenlib.h" 00044 #include "BLI_dynstr.h" 00045 #include "BLI_dlrbTree.h" 00046 #include "BLI_utildefines.h" 00047 00048 #include "DNA_anim_types.h" 00049 #include "DNA_armature_types.h" 00050 #include "DNA_object_types.h" 00051 #include "DNA_scene_types.h" 00052 00053 #include "BKE_animsys.h" 00054 #include "BKE_action.h" 00055 #include "BKE_armature.h" 00056 #include "BKE_depsgraph.h" 00057 #include "BKE_idprop.h" 00058 #include "BKE_library.h" 00059 00060 #include "BKE_context.h" 00061 #include "BKE_report.h" 00062 00063 #include "RNA_access.h" 00064 #include "RNA_define.h" 00065 #include "RNA_enum_types.h" 00066 00067 #include "WM_api.h" 00068 #include "WM_types.h" 00069 00070 #include "UI_interface.h" 00071 #include "UI_resources.h" 00072 00073 #include "ED_anim_api.h" 00074 #include "ED_armature.h" 00075 #include "ED_keyframes_draw.h" 00076 #include "ED_keyframing.h" 00077 #include "ED_keyframes_edit.h" 00078 #include "ED_screen.h" 00079 00080 #include "armature_intern.h" 00081 00082 /* ******* XXX ********** */ 00083 00084 static void action_set_activemarker(void *UNUSED(a), void *UNUSED(b), void *UNUSED(c)) {} 00085 00086 /* ************************************************************* */ 00087 /* == POSE-LIBRARY TOOL FOR BLENDER == 00088 * 00089 * Overview: 00090 * This tool allows animators to store a set of frequently used poses to dump into 00091 * the active action to help in "budget" productions to quickly block out new actions. 00092 * It acts as a kind of "glorified clipboard for poses", allowing for naming of poses. 00093 * 00094 * Features: 00095 * - PoseLibs are simply normal Actions 00096 * - Each "pose" is simply a set of keyframes that occur on a particular frame 00097 * -> a set of TimeMarkers that belong to each Action, help 'label' where a 'pose' can be 00098 * found in the Action 00099 * - The Scrollwheel or PageUp/Down buttons when used in a special mode or after pressing/holding 00100 * [a modifier] key, cycles through the poses available for the active pose's poselib, allowing the 00101 * animator to preview what action best suits that pose 00102 */ 00103 /* ************************************************************* */ 00104 00105 00106 /* gets the first available frame in poselib to store a pose on 00107 * - frames start from 1, and a pose should occur on every frame... 0 is error! 00108 */ 00109 static int poselib_get_free_index (bAction *act) 00110 { 00111 TimeMarker *marker; 00112 int low=0, high=0; 00113 00114 /* sanity checks */ 00115 if (ELEM(NULL, act, act->markers.first)) return 1; 00116 00117 /* loop over poses finding various values (poses are not stored in chronological order) */ 00118 for (marker= act->markers.first; marker; marker= marker->next) { 00119 /* only increase low if value is 1 greater than low, to find "gaps" where 00120 * poses were removed from the poselib 00121 */ 00122 if (marker->frame == (low + 1)) 00123 low++; 00124 00125 /* value replaces high if it is the highest value encountered yet */ 00126 if (marker->frame > high) 00127 high= marker->frame; 00128 } 00129 00130 /* - if low is not equal to high, then low+1 is a gap 00131 * - if low is equal to high, then high+1 is the next index (add at end) 00132 */ 00133 if (low < high) 00134 return (low + 1); 00135 else 00136 return (high + 1); 00137 } 00138 00139 /* returns the active pose for a poselib */ 00140 static TimeMarker *poselib_get_active_pose (bAction *act) 00141 { 00142 if ((act) && (act->active_marker)) 00143 return BLI_findlink(&act->markers, act->active_marker-1); 00144 else 00145 return NULL; 00146 } 00147 00148 /* Get object that Pose Lib should be found on */ 00149 /* XXX C can be zero */ 00150 static Object *get_poselib_object (bContext *C) 00151 { 00152 ScrArea *sa; 00153 00154 /* sanity check */ 00155 if (C == NULL) 00156 return NULL; 00157 00158 sa = CTX_wm_area(C); 00159 00160 if (sa && (sa->spacetype == SPACE_BUTS)) 00161 return CTX_data_pointer_get_type(C, "object", &RNA_Object).data; 00162 else 00163 return ED_object_pose_armature(CTX_data_active_object(C)); 00164 } 00165 00166 /* Poll callback for operators that require existing PoseLib data (with poses) to work */ 00167 static int has_poselib_pose_data_poll (bContext *C) 00168 { 00169 Object *ob = get_poselib_object(C); 00170 return (ob && ob->poselib); 00171 } 00172 00173 /* ----------------------------------- */ 00174 00175 /* Initialise a new poselib (whether it is needed or not) */ 00176 static bAction *poselib_init_new (Object *ob) 00177 { 00178 /* sanity checks - only for armatures */ 00179 if (ELEM(NULL, ob, ob->pose)) 00180 return NULL; 00181 00182 /* init object's poselib action (unlink old one if there) */ 00183 if (ob->poselib) 00184 id_us_min(&ob->poselib->id); 00185 ob->poselib= add_empty_action("PoseLib"); 00186 00187 return ob->poselib; 00188 } 00189 00190 /* Initialise a new poselib (checks if that needs to happen) */ 00191 static bAction *poselib_validate (Object *ob) 00192 { 00193 if (ELEM(NULL, ob, ob->pose)) 00194 return NULL; 00195 else if (ob->poselib == NULL) 00196 return poselib_init_new(ob); 00197 else 00198 return ob->poselib; 00199 } 00200 00201 /* ************************************************************* */ 00202 /* Pose Lib UI Operators */ 00203 00204 static int poselib_new_exec (bContext *C, wmOperator *UNUSED(op)) 00205 { 00206 Object *ob = get_poselib_object(C); 00207 00208 /* sanity checks */ 00209 if (ob == NULL) 00210 return OPERATOR_CANCELLED; 00211 00212 /* new method here deals with the rest... */ 00213 poselib_init_new(ob); 00214 00215 /* notifier here might evolve? */ 00216 WM_event_add_notifier(C, NC_OBJECT|ND_POSE, NULL); 00217 00218 return OPERATOR_FINISHED; 00219 } 00220 00221 void POSELIB_OT_new (wmOperatorType *ot) 00222 { 00223 /* identifiers */ 00224 ot->name = "New Pose Library"; 00225 ot->idname = "POSELIB_OT_new"; 00226 ot->description = "Add New Pose Library to active Object"; 00227 00228 /* callbacks */ 00229 ot->exec = poselib_new_exec; 00230 ot->poll= ED_operator_posemode; 00231 00232 /* flags */ 00233 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00234 } 00235 00236 /* ------------------------------------------------ */ 00237 00238 static int poselib_unlink_exec (bContext *C, wmOperator *UNUSED(op)) 00239 { 00240 Object *ob = get_poselib_object(C); 00241 00242 /* sanity checks */ 00243 if (ELEM(NULL, ob, ob->poselib)) 00244 return OPERATOR_CANCELLED; 00245 00246 /* there should be a poselib (we just checked above!), so just lower its user count and remove */ 00247 id_us_min(&ob->poselib->id); 00248 ob->poselib = NULL; 00249 00250 /* notifier here might evolve? */ 00251 WM_event_add_notifier(C, NC_OBJECT|ND_POSE, NULL); 00252 00253 return OPERATOR_FINISHED; 00254 } 00255 00256 void POSELIB_OT_unlink (wmOperatorType *ot) 00257 { 00258 /* identifiers */ 00259 ot->name = "Unlink Pose Library"; 00260 ot->idname = "POSELIB_OT_unlink"; 00261 ot->description = "Remove Pose Library from active Object"; 00262 00263 /* callbacks */ 00264 ot->exec = poselib_unlink_exec; 00265 ot->poll= has_poselib_pose_data_poll; 00266 00267 /* flags */ 00268 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00269 } 00270 00271 /* ************************************************************* */ 00272 /* Pose Editing Operators */ 00273 00274 /* This tool automagically generates/validates poselib data so that it corresponds to the data 00275 * in the action. This is for use in making existing actions usable as poselibs. 00276 */ 00277 static int poselib_sanitise_exec (bContext *C, wmOperator *op) 00278 { 00279 Object *ob = get_poselib_object(C); 00280 bAction *act = (ob)? ob->poselib : NULL; 00281 DLRBT_Tree keys; 00282 ActKeyColumn *ak; 00283 TimeMarker *marker, *markern; 00284 00285 /* validate action */ 00286 if (act == NULL) { 00287 BKE_report(op->reports, RPT_WARNING, "No Action to validate"); 00288 return OPERATOR_CANCELLED; 00289 } 00290 00291 /* determine which frames have keys */ 00292 BLI_dlrbTree_init(&keys); 00293 action_to_keylist(NULL, act, &keys, NULL); 00294 BLI_dlrbTree_linkedlist_sync(&keys); 00295 00296 /* for each key, make sure there is a corresponding pose */ 00297 for (ak= keys.first; ak; ak= ak->next) { 00298 /* check if any pose matches this */ 00299 // TODO: don't go looking through the list like this every time... 00300 for (marker= act->markers.first; marker; marker= marker->next) { 00301 if (IS_EQ(marker->frame, (double)ak->cfra)) { 00302 marker->flag = -1; 00303 break; 00304 } 00305 } 00306 00307 /* add new if none found */ 00308 if (marker == NULL) { 00309 /* add pose to poselib */ 00310 marker= MEM_callocN(sizeof(TimeMarker), "ActionMarker"); 00311 00312 BLI_strncpy(marker->name, "Pose", sizeof(marker->name)); 00313 00314 marker->frame= (int)ak->cfra; 00315 marker->flag= -1; 00316 00317 BLI_addtail(&act->markers, marker); 00318 } 00319 } 00320 00321 /* remove all untagged poses (unused), and remove all tags */ 00322 for (marker= act->markers.first; marker; marker= markern) { 00323 markern= marker->next; 00324 00325 if (marker->flag != -1) 00326 BLI_freelinkN(&act->markers, marker); 00327 else 00328 marker->flag = 0; 00329 } 00330 00331 /* free temp memory */ 00332 BLI_dlrbTree_free(&keys); 00333 00334 return OPERATOR_FINISHED; 00335 } 00336 00337 void POSELIB_OT_action_sanitise (wmOperatorType *ot) 00338 { 00339 /* identifiers */ 00340 ot->name = "Sanitise Pose Library Action"; 00341 ot->idname = "POSELIB_OT_action_sanitise"; 00342 ot->description = "Make action suitable for use as a Pose Library"; 00343 00344 /* callbacks */ 00345 ot->exec = poselib_sanitise_exec; 00346 ot->poll = has_poselib_pose_data_poll; 00347 00348 /* flags */ 00349 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00350 } 00351 00352 /* ------------------------------------------ */ 00353 00354 static void poselib_add_menu_invoke__replacemenu (bContext *C, uiLayout *layout, void *UNUSED(arg)) 00355 { 00356 Object *ob= get_poselib_object(C); 00357 bAction *act= ob->poselib; /* never NULL */ 00358 TimeMarker *marker; 00359 00360 /* set the operator execution context correctly */ 00361 uiLayoutSetOperatorContext(layout, WM_OP_EXEC_DEFAULT); 00362 00363 /* add each marker to this menu */ 00364 for (marker= act->markers.first; marker; marker= marker->next) { 00365 PointerRNA props_ptr; 00366 00367 props_ptr = uiItemFullO(layout, "POSELIB_OT_pose_add", 00368 marker->name, ICON_ARMATURE_DATA, NULL, 00369 WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS); 00370 00371 RNA_int_set(&props_ptr, "frame", marker->frame); 00372 RNA_string_set(&props_ptr, "name", marker->name); 00373 } 00374 } 00375 00376 static int poselib_add_menu_invoke (bContext *C, wmOperator *op, wmEvent *UNUSED(evt)) 00377 { 00378 Scene *scene= CTX_data_scene(C); 00379 Object *ob= get_poselib_object(C); 00380 bPose *pose= (ob) ? ob->pose : NULL; 00381 uiPopupMenu *pup; 00382 uiLayout *layout; 00383 00384 /* sanity check */ 00385 if (ELEM(NULL, ob, pose)) 00386 return OPERATOR_CANCELLED; 00387 00388 /* start building */ 00389 pup= uiPupMenuBegin(C, op->type->name, ICON_NONE); 00390 layout= uiPupMenuLayout(pup); 00391 uiLayoutSetOperatorContext(layout, WM_OP_EXEC_DEFAULT); 00392 00393 /* add new (adds to the first unoccupied frame) */ 00394 uiItemIntO(layout, "Add New", ICON_NONE, "POSELIB_OT_pose_add", "frame", poselib_get_free_index(ob->poselib)); 00395 00396 /* check if we have any choices to add a new pose in any other way */ 00397 if ((ob->poselib) && (ob->poselib->markers.first)) { 00398 /* add new (on current frame) */ 00399 uiItemIntO(layout, "Add New (Current Frame)", ICON_NONE, "POSELIB_OT_pose_add", "frame", CFRA); 00400 00401 /* replace existing - submenu */ 00402 uiItemMenuF(layout, "Replace Existing...", 0, poselib_add_menu_invoke__replacemenu, NULL); 00403 } 00404 00405 uiPupMenuEnd(C, pup); 00406 00407 /* this operator is only for a menu, not used further */ 00408 return OPERATOR_CANCELLED; 00409 } 00410 00411 00412 static int poselib_add_exec (bContext *C, wmOperator *op) 00413 { 00414 Object *ob= get_poselib_object(C); 00415 bAction *act = poselib_validate(ob); 00416 bPose *pose= (ob) ? ob->pose : NULL; 00417 TimeMarker *marker; 00418 KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Whole Character"); /* this includes custom props :)*/ 00419 int frame= RNA_int_get(op->ptr, "frame"); 00420 char name[64]; 00421 00422 /* sanity check (invoke should have checked this anyway) */ 00423 if (ELEM(NULL, ob, pose)) 00424 return OPERATOR_CANCELLED; 00425 00426 /* get name to give to pose */ 00427 RNA_string_get(op->ptr, "name", name); 00428 00429 /* add pose to poselib - replaces any existing pose there 00430 * - for the 'replace' option, this should end up finding the appropriate marker, 00431 * so no new one will be added 00432 */ 00433 for (marker= act->markers.first; marker; marker= marker->next) { 00434 if (marker->frame == frame) { 00435 BLI_strncpy(marker->name, name, sizeof(marker->name)); 00436 break; 00437 } 00438 } 00439 if (marker == NULL) { 00440 marker= MEM_callocN(sizeof(TimeMarker), "ActionMarker"); 00441 00442 BLI_strncpy(marker->name, name, sizeof(marker->name)); 00443 marker->frame= frame; 00444 00445 BLI_addtail(&act->markers, marker); 00446 } 00447 00448 /* validate name */ 00449 BLI_uniquename(&act->markers, marker, "Pose", '.', offsetof(TimeMarker, name), sizeof(marker->name)); 00450 00451 /* use Keying Set to determine what to store for the pose */ 00452 // FIXME: in the past, the Keying Set respected selections (LocRotScale), but the current one doesn't (Whole Character) 00453 // so perhaps we need either a new Keying Set, or just to add overrides here... 00454 ANIM_apply_keyingset(C, NULL, act, ks, MODIFYKEY_MODE_INSERT, (float)frame); 00455 00456 /* store new 'active' pose number */ 00457 act->active_marker= BLI_countlist(&act->markers); 00458 00459 /* done */ 00460 return OPERATOR_FINISHED; 00461 } 00462 00463 void POSELIB_OT_pose_add (wmOperatorType *ot) 00464 { 00465 /* identifiers */ 00466 ot->name= "PoseLib Add Pose"; 00467 ot->idname= "POSELIB_OT_pose_add"; 00468 ot->description= "Add the current Pose to the active Pose Library"; 00469 00470 /* api callbacks */ 00471 ot->invoke= poselib_add_menu_invoke; 00472 ot->exec= poselib_add_exec; 00473 ot->poll= ED_operator_posemode; 00474 00475 /* flags */ 00476 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00477 00478 /* properties */ 00479 RNA_def_int(ot->srna, "frame", 1, 0, INT_MAX, "Frame", "Frame to store pose on", 0, INT_MAX); 00480 RNA_def_string(ot->srna, "name", "Pose", 64, "Pose Name", "Name of newly added Pose"); 00481 } 00482 00483 /* ----- */ 00484 00485 /* can be called with C == NULL */ 00486 static EnumPropertyItem *poselib_stored_pose_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free) 00487 { 00488 Object *ob = get_poselib_object(C); 00489 bAction *act = (ob) ? ob->poselib : NULL; 00490 TimeMarker *marker; 00491 EnumPropertyItem *item= NULL, item_tmp= {0}; 00492 int totitem= 0; 00493 int i= 0; 00494 00495 if (C == NULL) { 00496 return DummyRNA_DEFAULT_items; 00497 } 00498 00499 /* check that the action exists */ 00500 if (act) { 00501 /* add each marker to the list */ 00502 for (marker=act->markers.first, i=0; marker; marker= marker->next, i++) { 00503 item_tmp.identifier= item_tmp.name= marker->name; 00504 item_tmp.icon= ICON_ARMATURE_DATA; 00505 item_tmp.value= i; 00506 RNA_enum_item_add(&item, &totitem, &item_tmp); 00507 } 00508 } 00509 00510 RNA_enum_item_end(&item, &totitem); 00511 *free= 1; 00512 00513 return item; 00514 } 00515 00516 static int poselib_remove_exec (bContext *C, wmOperator *op) 00517 { 00518 Object *ob= get_poselib_object(C); 00519 bAction *act= (ob) ? ob->poselib : NULL; 00520 TimeMarker *marker; 00521 FCurve *fcu; 00522 00523 /* check if valid poselib */ 00524 if (act == NULL) { 00525 BKE_report(op->reports, RPT_ERROR, "Object doesn't have PoseLib data"); 00526 return OPERATOR_CANCELLED; 00527 } 00528 00529 /* get index (and pointer) of pose to remove */ 00530 marker= BLI_findlink(&act->markers, RNA_enum_get(op->ptr, "pose")); 00531 if (marker == NULL) { 00532 BKE_reportf(op->reports, RPT_ERROR, "Invalid Pose specified %d", RNA_int_get(op->ptr, "pose")); 00533 return OPERATOR_CANCELLED; 00534 } 00535 00536 /* remove relevant keyframes */ 00537 for (fcu= act->curves.first; fcu; fcu= fcu->next) { 00538 BezTriple *bezt; 00539 unsigned int i; 00540 00541 if (fcu->bezt) { 00542 for (i=0, bezt=fcu->bezt; i < fcu->totvert; i++, bezt++) { 00543 /* check if remove */ 00544 if (IS_EQ(bezt->vec[1][0], marker->frame)) { 00545 delete_fcurve_key(fcu, i, 1); 00546 break; 00547 } 00548 } 00549 } 00550 } 00551 00552 /* remove poselib from list */ 00553 BLI_freelinkN(&act->markers, marker); 00554 00555 /* fix active pose number */ 00556 act->active_marker= 0; 00557 00558 /* done */ 00559 return OPERATOR_FINISHED; 00560 } 00561 00562 void POSELIB_OT_pose_remove (wmOperatorType *ot) 00563 { 00564 PropertyRNA *prop; 00565 00566 /* identifiers */ 00567 ot->name= "PoseLib Remove Pose"; 00568 ot->idname= "POSELIB_OT_pose_remove"; 00569 ot->description= "Remove nth pose from the active Pose Library"; 00570 00571 /* api callbacks */ 00572 ot->invoke= WM_menu_invoke; 00573 ot->exec= poselib_remove_exec; 00574 ot->poll= has_poselib_pose_data_poll; 00575 00576 /* flags */ 00577 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00578 00579 /* properties */ 00580 prop= RNA_def_enum(ot->srna, "pose", DummyRNA_DEFAULT_items, 0, "Pose", "The pose to remove"); 00581 RNA_def_enum_funcs(prop, poselib_stored_pose_itemf); 00582 ot->prop= prop; 00583 } 00584 00585 static int poselib_rename_invoke (bContext *C, wmOperator *op, wmEvent *evt) 00586 { 00587 Object *ob= get_poselib_object(C); 00588 bAction *act= (ob) ? ob->poselib : NULL; 00589 TimeMarker *marker; 00590 00591 /* check if valid poselib */ 00592 if (act == NULL) { 00593 BKE_report(op->reports, RPT_ERROR, "Object doesn't have PoseLib data"); 00594 return OPERATOR_CANCELLED; 00595 } 00596 00597 /* get index (and pointer) of pose to remove */ 00598 marker= BLI_findlink(&act->markers, act->active_marker-1); 00599 if (marker == NULL) { 00600 BKE_report(op->reports, RPT_ERROR, "Invalid index for Pose"); 00601 return OPERATOR_CANCELLED; 00602 } 00603 else { 00604 /* use the existing name of the marker as the name, and use the active marker as the one to rename */ 00605 RNA_enum_set(op->ptr, "pose", act->active_marker-1); 00606 RNA_string_set(op->ptr, "name", marker->name); 00607 } 00608 00609 /* part to sync with other similar operators... */ 00610 return WM_operator_props_popup(C, op, evt); 00611 } 00612 00613 static int poselib_rename_exec (bContext *C, wmOperator *op) 00614 { 00615 Object *ob= ED_object_pose_armature(CTX_data_active_object(C)); 00616 bAction *act= (ob) ? ob->poselib : NULL; 00617 TimeMarker *marker; 00618 char newname[64]; 00619 00620 /* check if valid poselib */ 00621 if (act == NULL) { 00622 BKE_report(op->reports, RPT_ERROR, "Object doesn't have PoseLib data"); 00623 return OPERATOR_CANCELLED; 00624 } 00625 00626 /* get index (and pointer) of pose to remove */ 00627 marker= BLI_findlink(&act->markers, RNA_int_get(op->ptr, "pose")); 00628 if (marker == NULL) { 00629 BKE_report(op->reports, RPT_ERROR, "Invalid index for Pose"); 00630 return OPERATOR_CANCELLED; 00631 } 00632 00633 /* get new name */ 00634 RNA_string_get(op->ptr, "name", newname); 00635 00636 /* copy name and validate it */ 00637 BLI_strncpy(marker->name, newname, sizeof(marker->name)); 00638 BLI_uniquename(&act->markers, marker, "Pose", '.', offsetof(TimeMarker, name), sizeof(marker->name)); 00639 00640 /* done */ 00641 return OPERATOR_FINISHED; 00642 } 00643 00644 void POSELIB_OT_pose_rename (wmOperatorType *ot) 00645 { 00646 PropertyRNA *prop; 00647 static EnumPropertyItem prop_poses_dummy_types[] = { 00648 {0, NULL, 0, NULL, NULL} 00649 }; 00650 00651 /* identifiers */ 00652 ot->name= "PoseLib Rename Pose"; 00653 ot->idname= "POSELIB_OT_pose_rename"; 00654 ot->description= "Rename specified pose from the active Pose Library"; 00655 00656 /* api callbacks */ 00657 ot->invoke= poselib_rename_invoke; 00658 ot->exec= poselib_rename_exec; 00659 ot->poll= has_poselib_pose_data_poll; 00660 00661 /* flags */ 00662 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00663 00664 /* properties */ 00665 /* NOTE: name not pose is the operator's "main" property, so that it will get activated in the popup for easy renaming */ 00666 ot->prop= RNA_def_string(ot->srna, "name", "RenamedPose", 64, "New Pose Name", "New name for pose"); 00667 prop= RNA_def_enum(ot->srna, "pose", prop_poses_dummy_types, 0, "Pose", "The pose to rename"); 00668 RNA_def_enum_funcs(prop, poselib_stored_pose_itemf); 00669 } 00670 00671 /* ************************************************************* */ 00672 /* Pose-Lib Browsing/Previewing Operator */ 00673 00674 /* Simple struct for storing settings/data for use during PoseLib preview */ 00675 typedef struct tPoseLib_PreviewData { 00676 ListBase backups; /* tPoseLib_Backup structs for restoring poses */ 00677 ListBase searchp; /* LinkData structs storing list of poses which match the current search-string */ 00678 00679 Scene *scene; /* active scene */ 00680 ScrArea *sa; /* active area */ 00681 00682 PointerRNA rna_ptr; /* RNA-Pointer to Object 'ob' */ 00683 Object *ob; /* object to work on */ 00684 bArmature *arm; /* object's armature data */ 00685 bPose *pose; /* object's pose */ 00686 bAction *act; /* poselib to use */ 00687 TimeMarker *marker; /* 'active' pose */ 00688 00689 int selcount; /* number of selected elements to work on */ 00690 int totcount; /* total number of elements to work on */ 00691 00692 short state; /* state of main loop */ 00693 short redraw; /* redraw/update settings during main loop */ 00694 short flag; /* flags for various settings */ 00695 00696 short search_cursor; /* position of cursor in searchstr (cursor occurs before the item at the nominated index) */ 00697 char searchstr[64]; /* (Part of) Name to search for to filter poses that get shown */ 00698 char searchold[64]; /* Previously set searchstr (from last loop run), so that we can detected when to rebuild searchp */ 00699 00700 char headerstr[200]; /* Info-text to print in header */ 00701 } tPoseLib_PreviewData; 00702 00703 /* defines for tPoseLib_PreviewData->state values */ 00704 enum { 00705 PL_PREVIEW_ERROR = -1, 00706 PL_PREVIEW_RUNNING, 00707 PL_PREVIEW_CONFIRM, 00708 PL_PREVIEW_CANCEL, 00709 PL_PREVIEW_RUNONCE 00710 }; 00711 00712 /* defines for tPoseLib_PreviewData->redraw values */ 00713 enum { 00714 PL_PREVIEW_NOREDRAW = 0, 00715 PL_PREVIEW_REDRAWALL, 00716 PL_PREVIEW_REDRAWHEADER, 00717 }; 00718 00719 /* defines for tPoseLib_PreviewData->flag values */ 00720 enum { 00721 PL_PREVIEW_FIRSTTIME = (1<<0), 00722 PL_PREVIEW_SHOWORIGINAL = (1<<1) 00723 }; 00724 00725 /* ---------------------------- */ 00726 00727 /* simple struct for storing backup info */ 00728 typedef struct tPoseLib_Backup { 00729 struct tPoseLib_Backup *next, *prev; 00730 00731 bPoseChannel *pchan; /* pose channel backups are for */ 00732 00733 bPoseChannel olddata; /* copy of pose channel's old data (at start) */ 00734 IDProperty *oldprops; /* copy (needs freeing) of pose channel's properties (at start) */ 00735 } tPoseLib_Backup; 00736 00737 /* Makes a copy of the current pose for restoration purposes - doesn't do constraints currently */ 00738 static void poselib_backup_posecopy (tPoseLib_PreviewData *pld) 00739 { 00740 bActionGroup *agrp; 00741 bPoseChannel *pchan; 00742 00743 /* for each posechannel that has an actionchannel in */ 00744 for (agrp= pld->act->groups.first; agrp; agrp= agrp->next) { 00745 /* try to find posechannel */ 00746 pchan= get_pose_channel(pld->pose, agrp->name); 00747 00748 /* backup data if available */ 00749 if (pchan) { 00750 tPoseLib_Backup *plb; 00751 00752 /* store backup */ 00753 plb= MEM_callocN(sizeof(tPoseLib_Backup), "tPoseLib_Backup"); 00754 00755 plb->pchan= pchan; 00756 memcpy(&plb->olddata, plb->pchan, sizeof(bPoseChannel)); 00757 00758 if (pchan->prop) 00759 plb->oldprops= IDP_CopyProperty(pchan->prop); 00760 00761 BLI_addtail(&pld->backups, plb); 00762 00763 /* mark as being affected */ 00764 if ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED)) 00765 pld->selcount++; 00766 pld->totcount++; 00767 } 00768 } 00769 } 00770 00771 /* Restores original pose */ 00772 static void poselib_backup_restore (tPoseLib_PreviewData *pld) 00773 { 00774 tPoseLib_Backup *plb; 00775 00776 for (plb= pld->backups.first; plb; plb= plb->next) { 00777 /* copy most of data straight back */ 00778 memcpy(plb->pchan, &plb->olddata, sizeof(bPoseChannel)); 00779 00780 /* just overwrite values of properties from the stored copies (there should be some) */ 00781 if (plb->oldprops) 00782 IDP_SyncGroupValues(plb->pchan->prop, plb->oldprops); 00783 00784 // TODO: constraints settings aren't restored yet, even though these could change (though not that likely) 00785 } 00786 } 00787 00788 /* Free list of backups, including any side data it may use */ 00789 static void poselib_backup_free_data (tPoseLib_PreviewData *pld) 00790 { 00791 tPoseLib_Backup *plb, *plbn; 00792 00793 for (plb= pld->backups.first; plb; plb= plbn) { 00794 plbn= plb->next; 00795 00796 /* free custom data */ 00797 if (plb->oldprops) { 00798 IDP_FreeProperty(plb->oldprops); 00799 MEM_freeN(plb->oldprops); 00800 } 00801 00802 /* free backup element now */ 00803 BLI_freelinkN(&pld->backups, plb); 00804 } 00805 } 00806 00807 /* ---------------------------- */ 00808 00809 /* Applies the appropriate stored pose from the pose-library to the current pose 00810 * - assumes that a valid object, with a poselib has been supplied 00811 * - gets the string to print in the header 00812 * - this code is based on the code for extract_pose_from_action in blenkernel/action.c 00813 */ 00814 static void poselib_apply_pose (tPoseLib_PreviewData *pld) 00815 { 00816 PointerRNA *ptr= &pld->rna_ptr; 00817 bArmature *arm= pld->arm; 00818 bPose *pose= pld->pose; 00819 bPoseChannel *pchan; 00820 bAction *act= pld->act; 00821 bActionGroup *agrp; 00822 00823 KeyframeEditData ked= {{NULL}}; 00824 KeyframeEditFunc group_ok_cb; 00825 int frame= 1; 00826 00827 /* get the frame */ 00828 if (pld->marker) 00829 frame= pld->marker->frame; 00830 else 00831 return; 00832 00833 00834 /* init settings for testing groups for keyframes */ 00835 group_ok_cb= ANIM_editkeyframes_ok(BEZT_OK_FRAMERANGE); 00836 ked.f1= ((float)frame) - 0.5f; 00837 ked.f2= ((float)frame) + 0.5f; 00838 00839 00840 /* start applying - only those channels which have a key at this point in time! */ 00841 for (agrp= act->groups.first; agrp; agrp= agrp->next) { 00842 /* check if group has any keyframes */ 00843 if (ANIM_animchanneldata_keyframes_loop(&ked, agrp, ALE_GROUP, NULL, group_ok_cb, NULL, 0)) { 00844 /* has keyframe on this frame, so try to get a PoseChannel with this name */ 00845 pchan= get_pose_channel(pose, agrp->name); 00846 00847 if (pchan) { 00848 short ok= 0; 00849 00850 /* check if this bone should get any animation applied */ 00851 if (pld->selcount == 0) { 00852 /* if no bones are selected, then any bone is ok */ 00853 ok= 1; 00854 } 00855 else if (pchan->bone) { 00856 /* only ok if bone is visible and selected */ 00857 if ( (pchan->bone->flag & BONE_SELECTED) && 00858 (pchan->bone->flag & BONE_HIDDEN_P)==0 && 00859 (pchan->bone->layer & arm->layer) ) 00860 ok = 1; 00861 } 00862 00863 if (ok) 00864 animsys_evaluate_action_group(ptr, act, agrp, NULL, (float)frame); 00865 } 00866 } 00867 } 00868 } 00869 00870 /* Auto-keys/tags bones affected by the pose used from the poselib */ 00871 static void poselib_keytag_pose (bContext *C, Scene *scene, tPoseLib_PreviewData *pld) 00872 { 00873 bPose *pose= pld->pose; 00874 bPoseChannel *pchan; 00875 bAction *act= pld->act; 00876 bActionGroup *agrp; 00877 00878 KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, "Whole Character"); 00879 ListBase dsources = {NULL, NULL}; 00880 short autokey = autokeyframe_cfra_can_key(scene, &pld->ob->id); 00881 00882 /* start tagging/keying */ 00883 for (agrp= act->groups.first; agrp; agrp= agrp->next) { 00884 /* only for selected action channels */ 00885 if (agrp->flag & AGRP_SELECTED) { 00886 pchan= get_pose_channel(pose, agrp->name); 00887 00888 if (pchan) { 00889 if (autokey) { 00890 /* add datasource override for the PoseChannel, to be used later */ 00891 ANIM_relative_keyingset_add_source(&dsources, &pld->ob->id, &RNA_PoseBone, pchan); 00892 00893 /* clear any unkeyed tags */ 00894 if (pchan->bone) 00895 pchan->bone->flag &= ~BONE_UNKEYED; 00896 } 00897 else { 00898 /* add unkeyed tags */ 00899 if (pchan->bone) 00900 pchan->bone->flag |= BONE_UNKEYED; 00901 } 00902 } 00903 } 00904 } 00905 00906 /* perform actual auto-keying now */ 00907 if (autokey) { 00908 /* insert keyframes for all relevant bones in one go */ 00909 ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA); 00910 BLI_freelistN(&dsources); 00911 } 00912 00913 /* send notifiers for this */ 00914 WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_EDITED, NULL); 00915 } 00916 00917 /* Apply the relevant changes to the pose */ 00918 static void poselib_preview_apply (bContext *C, wmOperator *op) 00919 { 00920 tPoseLib_PreviewData *pld= (tPoseLib_PreviewData *)op->customdata; 00921 00922 /* only recalc pose (and its dependencies) if pose has changed */ 00923 if (pld->redraw == PL_PREVIEW_REDRAWALL) { 00924 /* don't clear pose if firsttime */ 00925 if ((pld->flag & PL_PREVIEW_FIRSTTIME)==0) 00926 poselib_backup_restore(pld); 00927 else 00928 pld->flag &= ~PL_PREVIEW_FIRSTTIME; 00929 00930 /* pose should be the right one to draw (unless we're temporarily not showing it) */ 00931 if ((pld->flag & PL_PREVIEW_SHOWORIGINAL)==0) { 00932 RNA_int_set(op->ptr, "pose_index", BLI_findindex(&pld->act->markers, pld->marker)); 00933 poselib_apply_pose(pld); 00934 } 00935 else 00936 RNA_int_set(op->ptr, "pose_index", -2); /* -2 means don't apply any pose */ 00937 00938 /* old optimize trick... this enforces to bypass the depgraph 00939 * - note: code copied from transform_generics.c -> recalcData() 00940 */ 00941 // FIXME: shouldn't this use the builtin stuff? 00942 if ((pld->arm->flag & ARM_DELAYDEFORM)==0) 00943 DAG_id_tag_update(&pld->ob->id, OB_RECALC_DATA); /* sets recalc flags */ 00944 else 00945 where_is_pose(pld->scene, pld->ob); 00946 } 00947 00948 /* do header print - if interactively previewing */ 00949 if (pld->state == PL_PREVIEW_RUNNING) { 00950 if (pld->flag & PL_PREVIEW_SHOWORIGINAL) { 00951 sprintf(pld->headerstr, "PoseLib Previewing Pose: [Showing Original Pose] | Use Tab to start previewing poses again"); 00952 ED_area_headerprint(pld->sa, pld->headerstr); 00953 } 00954 else if (pld->searchstr[0]) { 00955 char tempstr[65]; 00956 char markern[64]; 00957 short index; 00958 00959 /* get search-string */ 00960 index= pld->search_cursor; 00961 00962 if (index >= 0 && index <= 64) { 00963 memcpy(&tempstr[0], &pld->searchstr[0], index); 00964 tempstr[index]= '|'; 00965 memcpy(&tempstr[index+1], &pld->searchstr[index], 64-index); 00966 } 00967 else { 00968 strncpy(tempstr, pld->searchstr, 64); 00969 } 00970 00971 /* get marker name */ 00972 if (pld->marker) 00973 strcpy(markern, pld->marker->name); 00974 else 00975 strcpy(markern, "No Matches"); 00976 00977 sprintf(pld->headerstr, "PoseLib Previewing Pose: Filter - [%s] | Current Pose - \"%s\" | Use ScrollWheel or PageUp/Down to change", tempstr, markern); 00978 ED_area_headerprint(pld->sa, pld->headerstr); 00979 } 00980 else { 00981 sprintf(pld->headerstr, "PoseLib Previewing Pose: \"%s\" | Use ScrollWheel or PageUp/Down to change", pld->marker->name); 00982 ED_area_headerprint(pld->sa, pld->headerstr); 00983 } 00984 } 00985 00986 /* request drawing of view + clear redraw flag */ 00987 WM_event_add_notifier(C, NC_OBJECT|ND_POSE, pld->ob); 00988 pld->redraw= PL_PREVIEW_NOREDRAW; 00989 } 00990 00991 /* ---------------------------- */ 00992 00993 /* This helper function is called during poselib_preview_poses to find the 00994 * pose to preview next (after a change event) 00995 */ 00996 static void poselib_preview_get_next (tPoseLib_PreviewData *pld, int step) 00997 { 00998 /* stop if not going anywhere, as we assume that there is a direction to move in */ 00999 if (step == 0) 01000 return; 01001 01002 /* search-string dictates a special approach */ 01003 if (pld->searchstr[0]) { 01004 TimeMarker *marker; 01005 LinkData *ld, *ldn, *ldc; 01006 01007 /* free and rebuild if needed (i.e. if search-str changed) */ 01008 if (strcmp(pld->searchstr, pld->searchold)) { 01009 /* free list of temporary search matches */ 01010 BLI_freelistN(&pld->searchp); 01011 01012 /* generate a new list of search matches */ 01013 for (marker= pld->act->markers.first; marker; marker= marker->next) { 01014 /* does the name partially match? 01015 * - don't worry about case, to make it easier for users to quickly input a name (or 01016 * part of one), which is the whole point of this feature 01017 */ 01018 if (BLI_strcasestr(marker->name, pld->searchstr)) { 01019 /* make link-data to store reference to it */ 01020 ld= MEM_callocN(sizeof(LinkData), "PoseMatch"); 01021 ld->data= marker; 01022 BLI_addtail(&pld->searchp, ld); 01023 } 01024 } 01025 01026 /* set current marker to NULL (so that we start from first) */ 01027 pld->marker= NULL; 01028 } 01029 01030 /* check if any matches */ 01031 if (pld->searchp.first == NULL) { 01032 pld->marker= NULL; 01033 return; 01034 } 01035 01036 /* find first match */ 01037 for (ldc= pld->searchp.first; ldc; ldc= ldc->next) { 01038 if (ldc->data == pld->marker) 01039 break; 01040 } 01041 if (ldc == NULL) 01042 ldc= pld->searchp.first; 01043 01044 /* Loop through the matches in a cyclic fashion, incrementing/decrementing step as appropriate 01045 * until step == 0. At this point, marker should be the correct marker. 01046 */ 01047 if (step > 0) { 01048 for (ld=ldc; ld && step; ld=ldn, step--) 01049 ldn= (ld->next) ? ld->next : pld->searchp.first; 01050 } 01051 else { 01052 for (ld=ldc; ld && step; ld=ldn, step++) 01053 ldn= (ld->prev) ? ld->prev : pld->searchp.last; 01054 } 01055 01056 /* set marker */ 01057 if (ld) 01058 pld->marker= ld->data; 01059 } 01060 else { 01061 TimeMarker *marker, *next; 01062 01063 /* if no marker, because we just ended searching, then set that to the start of the list */ 01064 if (pld->marker == NULL) 01065 pld->marker= pld->act->markers.first; 01066 01067 /* Loop through the markers in a cyclic fashion, incrementing/decrementing step as appropriate 01068 * until step == 0. At this point, marker should be the correct marker. 01069 */ 01070 if (step > 0) { 01071 for (marker=pld->marker; marker && step; marker=next, step--) 01072 next= (marker->next) ? marker->next : pld->act->markers.first; 01073 } 01074 else { 01075 for (marker=pld->marker; marker && step; marker=next, step++) 01076 next= (marker->prev) ? marker->prev : pld->act->markers.last; 01077 } 01078 01079 /* it should be fairly impossible for marker to be NULL */ 01080 if (marker) 01081 pld->marker= marker; 01082 } 01083 } 01084 01085 /* specially handle events for searching */ 01086 static void poselib_preview_handle_search (tPoseLib_PreviewData *pld, unsigned short event, char ascii) 01087 { 01088 /* try doing some form of string manipulation first */ 01089 switch (event) { 01090 case BACKSPACEKEY: 01091 if (pld->searchstr[0] && pld->search_cursor) { 01092 short len= strlen(pld->searchstr); 01093 short index= pld->search_cursor; 01094 short i; 01095 01096 for (i = index; i <= len; i++) 01097 pld->searchstr[i-1] = pld->searchstr[i]; 01098 01099 pld->search_cursor--; 01100 01101 poselib_preview_get_next(pld, 1); 01102 pld->redraw = PL_PREVIEW_REDRAWALL; 01103 return; 01104 } 01105 break; 01106 01107 case DELKEY: 01108 if (pld->searchstr[0] && pld->searchstr[1]) { 01109 short len= strlen(pld->searchstr); 01110 short index= pld->search_cursor; 01111 int i; 01112 01113 if (index < len) { 01114 for (i = index; i < len; i++) 01115 pld->searchstr[i] = pld->searchstr[i+1]; 01116 01117 poselib_preview_get_next(pld, 1); 01118 pld->redraw = PL_PREVIEW_REDRAWALL; 01119 return; 01120 } 01121 } 01122 break; 01123 } 01124 01125 if (ascii) { 01126 /* character to add to the string */ 01127 short index= pld->search_cursor; 01128 short len= (pld->searchstr[0]) ? strlen(pld->searchstr) : 0; 01129 short i; 01130 01131 if (len) { 01132 for (i = len; i > index; i--) 01133 pld->searchstr[i]= pld->searchstr[i-1]; 01134 } 01135 else 01136 pld->searchstr[1]= 0; 01137 01138 pld->searchstr[index]= ascii; 01139 pld->search_cursor++; 01140 01141 poselib_preview_get_next(pld, 1); 01142 pld->redraw = PL_PREVIEW_REDRAWALL; 01143 } 01144 } 01145 01146 /* handle events for poselib_preview_poses */ 01147 static int poselib_preview_handle_event (bContext *UNUSED(C), wmOperator *op, wmEvent *event) 01148 { 01149 tPoseLib_PreviewData *pld= op->customdata; 01150 int ret = OPERATOR_RUNNING_MODAL; 01151 01152 /* only accept 'press' event, and ignore 'release', so that we don't get double actions */ 01153 if (ELEM(event->val, KM_PRESS, KM_NOTHING) == 0) { 01154 //printf("PoseLib: skipping event with type '%s' and val %d\n", WM_key_event_string(event->type), event->val); 01155 return ret; 01156 } 01157 01158 /* backup stuff that needs to occur before every operation 01159 * - make a copy of searchstr, so that we know if cache needs to be rebuilt 01160 */ 01161 strcpy(pld->searchold, pld->searchstr); 01162 01163 /* if we're currently showing the original pose, only certain events are handled */ 01164 if (pld->flag & PL_PREVIEW_SHOWORIGINAL) { 01165 switch (event->type) { 01166 /* exit - cancel */ 01167 case ESCKEY: 01168 case RIGHTMOUSE: 01169 pld->state= PL_PREVIEW_CANCEL; 01170 break; 01171 01172 /* exit - confirm */ 01173 case LEFTMOUSE: 01174 case RETKEY: 01175 case PADENTER: 01176 case SPACEKEY: 01177 pld->state= PL_PREVIEW_CONFIRM; 01178 break; 01179 01180 /* view manipulation */ 01181 /* we add pass through here, so that the operators responsible for these can still run, 01182 * even though we still maintain control (as RUNNING_MODAL flag is still set too) 01183 */ 01184 case PAD0: case PAD1: case PAD2: case PAD3: case PAD4: 01185 case PAD5: case PAD6: case PAD7: case PAD8: case PAD9: 01186 case PADPLUSKEY: case PADMINUS: 01187 case MIDDLEMOUSE: case MOUSEMOVE: 01188 //pld->redraw= PL_PREVIEW_REDRAWHEADER; 01189 ret = OPERATOR_PASS_THROUGH; 01190 break; 01191 01192 /* quicky compare to original */ 01193 case TABKEY: 01194 pld->flag &= ~PL_PREVIEW_SHOWORIGINAL; 01195 pld->redraw= PL_PREVIEW_REDRAWALL; 01196 break; 01197 } 01198 01199 /* EXITS HERE... */ 01200 return ret; 01201 } 01202 01203 /* NORMAL EVENT HANDLING... */ 01204 /* searching takes priority over normal activity */ 01205 switch (event->type) { 01206 /* exit - cancel */ 01207 case ESCKEY: 01208 case RIGHTMOUSE: 01209 pld->state= PL_PREVIEW_CANCEL; 01210 break; 01211 01212 /* exit - confirm */ 01213 case LEFTMOUSE: 01214 case RETKEY: 01215 case PADENTER: 01216 case SPACEKEY: 01217 pld->state= PL_PREVIEW_CONFIRM; 01218 break; 01219 01220 /* toggle between original pose and poselib pose*/ 01221 case TABKEY: 01222 pld->flag |= PL_PREVIEW_SHOWORIGINAL; 01223 pld->redraw= PL_PREVIEW_REDRAWALL; 01224 break; 01225 01226 /* change to previous pose (cyclic) */ 01227 case PAGEUPKEY: 01228 case WHEELUPMOUSE: 01229 poselib_preview_get_next(pld, -1); 01230 pld->redraw= PL_PREVIEW_REDRAWALL; 01231 break; 01232 01233 /* change to next pose (cyclic) */ 01234 case PAGEDOWNKEY: 01235 case WHEELDOWNMOUSE: 01236 poselib_preview_get_next(pld, 1); 01237 pld->redraw= PL_PREVIEW_REDRAWALL; 01238 break; 01239 01240 /* jump 5 poses (cyclic, back) */ 01241 case DOWNARROWKEY: 01242 poselib_preview_get_next(pld, -5); 01243 pld->redraw= PL_PREVIEW_REDRAWALL; 01244 break; 01245 01246 /* jump 5 poses (cyclic, forward) */ 01247 case UPARROWKEY: 01248 poselib_preview_get_next(pld, 5); 01249 pld->redraw= PL_PREVIEW_REDRAWALL; 01250 break; 01251 01252 /* change to next pose or searching cursor control */ 01253 case RIGHTARROWKEY: 01254 if (pld->searchstr[0]) { 01255 /* move text-cursor to the right */ 01256 if (pld->search_cursor < strlen(pld->searchstr)) 01257 pld->search_cursor++; 01258 pld->redraw= PL_PREVIEW_REDRAWHEADER; 01259 } 01260 else { 01261 /* change to next pose (cyclic) */ 01262 poselib_preview_get_next(pld, 1); 01263 pld->redraw= PL_PREVIEW_REDRAWALL; 01264 } 01265 break; 01266 01267 /* change to next pose or searching cursor control */ 01268 case LEFTARROWKEY: 01269 if (pld->searchstr[0]) { 01270 /* move text-cursor to the left */ 01271 if (pld->search_cursor) 01272 pld->search_cursor--; 01273 pld->redraw= PL_PREVIEW_REDRAWHEADER; 01274 } 01275 else { 01276 /* change to previous pose (cyclic) */ 01277 poselib_preview_get_next(pld, -1); 01278 pld->redraw= PL_PREVIEW_REDRAWALL; 01279 } 01280 break; 01281 01282 /* change to first pose or start of searching string */ 01283 case HOMEKEY: 01284 if (pld->searchstr[0]) { 01285 pld->search_cursor= 0; 01286 pld->redraw= PL_PREVIEW_REDRAWHEADER; 01287 } 01288 else { 01289 /* change to first pose */ 01290 pld->marker= pld->act->markers.first; 01291 pld->act->active_marker= 1; 01292 01293 pld->redraw= PL_PREVIEW_REDRAWALL; 01294 } 01295 break; 01296 01297 /* change to last pose or start of searching string */ 01298 case ENDKEY: 01299 if (pld->searchstr[0]) { 01300 pld->search_cursor= strlen(pld->searchstr); 01301 pld->redraw= PL_PREVIEW_REDRAWHEADER; 01302 } 01303 else { 01304 /* change to last pose */ 01305 pld->marker= pld->act->markers.last; 01306 pld->act->active_marker= BLI_countlist(&pld->act->markers); 01307 01308 pld->redraw= PL_PREVIEW_REDRAWALL; 01309 } 01310 break; 01311 01312 /* view manipulation */ 01313 /* we add pass through here, so that the operators responsible for these can still run, 01314 * even though we still maintain control (as RUNNING_MODAL flag is still set too) 01315 */ 01316 case MIDDLEMOUSE: case MOUSEMOVE: 01317 //pld->redraw= PL_PREVIEW_REDRAWHEADER; 01318 ret = OPERATOR_PASS_THROUGH; 01319 break; 01320 01321 /* view manipulation, or searching */ 01322 case PAD0: case PAD1: case PAD2: case PAD3: case PAD4: 01323 case PAD5: case PAD6: case PAD7: case PAD8: case PAD9: 01324 case PADPLUSKEY: case PADMINUS: 01325 if (pld->searchstr[0]) { 01326 /* searching... */ 01327 poselib_preview_handle_search(pld, event->type, event->ascii); 01328 } 01329 else { 01330 /* view manipulation (see above) */ 01331 //pld->redraw= PL_PREVIEW_REDRAWHEADER; 01332 ret = OPERATOR_PASS_THROUGH; 01333 } 01334 break; 01335 01336 /* otherwise, assume that searching might be able to handle it */ 01337 default: 01338 poselib_preview_handle_search(pld, event->type, event->ascii); 01339 break; 01340 } 01341 01342 return ret; 01343 } 01344 01345 /* ---------------------------- */ 01346 01347 /* Init PoseLib Previewing data */ 01348 static void poselib_preview_init_data (bContext *C, wmOperator *op) 01349 { 01350 tPoseLib_PreviewData *pld; 01351 Object *ob= get_poselib_object(C); 01352 int pose_index = RNA_int_get(op->ptr, "pose_index"); 01353 01354 /* set up preview state info */ 01355 op->customdata= pld= MEM_callocN(sizeof(tPoseLib_PreviewData), "PoseLib Preview Data"); 01356 01357 /* get basic data */ 01358 pld->ob= ob; 01359 pld->arm= (ob) ? (ob->data) : NULL; 01360 pld->pose= (ob) ? (ob->pose) : NULL; 01361 pld->act= (ob) ? (ob->poselib) : NULL; 01362 01363 pld->scene= CTX_data_scene(C); 01364 pld->sa= CTX_wm_area(C); 01365 01366 /* get starting pose based on RNA-props for this operator */ 01367 if (pose_index == -1) 01368 pld->marker= poselib_get_active_pose(pld->act); 01369 else if (pose_index == -2) 01370 pld->flag |= PL_PREVIEW_SHOWORIGINAL; 01371 else 01372 pld->marker= (pld->act) ? BLI_findlink(&pld->act->markers, pose_index) : NULL; 01373 01374 /* check if valid poselib */ 01375 if (ELEM3(NULL, pld->ob, pld->pose, pld->arm)) { 01376 BKE_report(op->reports, RPT_ERROR, "PoseLib is only for Armatures in PoseMode"); 01377 pld->state= PL_PREVIEW_ERROR; 01378 return; 01379 } 01380 if (pld->act == NULL) { 01381 BKE_report(op->reports, RPT_ERROR, "Object doesn't have a valid PoseLib"); 01382 pld->state= PL_PREVIEW_ERROR; 01383 return; 01384 } 01385 if (pld->marker == NULL) { 01386 if (pld->act->markers.first) { 01387 /* just use first one then... */ 01388 pld->marker= pld->act->markers.first; 01389 if (pose_index > -2) 01390 BKE_report(op->reports, RPT_WARNING, "PoseLib had no active pose"); 01391 } 01392 else { 01393 BKE_report(op->reports, RPT_ERROR, "PoseLib has no poses to preview/apply"); 01394 pld->state= PL_PREVIEW_ERROR; 01395 return; 01396 } 01397 } 01398 01399 /* get ID pointer for applying poses */ 01400 RNA_id_pointer_create(&ob->id, &pld->rna_ptr); 01401 01402 /* make backups for restoring pose */ 01403 poselib_backup_posecopy(pld); 01404 01405 /* set flags for running */ 01406 pld->state= PL_PREVIEW_RUNNING; 01407 pld->redraw= PL_PREVIEW_REDRAWALL; 01408 pld->flag |= PL_PREVIEW_FIRSTTIME; 01409 01410 /* set depsgraph flags */ 01411 /* make sure the lock is set OK, unlock can be accidentally saved? */ 01412 pld->pose->flag |= POSE_LOCKED; 01413 pld->pose->flag &= ~POSE_DO_UNLOCK; 01414 01415 /* clear strings + search */ 01416 strcpy(pld->headerstr, ""); 01417 strcpy(pld->searchstr, ""); 01418 strcpy(pld->searchold, ""); 01419 pld->search_cursor= 0; 01420 } 01421 01422 /* After previewing poses */ 01423 static void poselib_preview_cleanup (bContext *C, wmOperator *op) 01424 { 01425 tPoseLib_PreviewData *pld= (tPoseLib_PreviewData *)op->customdata; 01426 Scene *scene= pld->scene; 01427 Object *ob= pld->ob; 01428 bPose *pose= pld->pose; 01429 bArmature *arm= pld->arm; 01430 bAction *act= pld->act; 01431 TimeMarker *marker= pld->marker; 01432 01433 /* redraw the header so that it doesn't show any of our stuff anymore */ 01434 ED_area_headerprint(pld->sa, NULL); 01435 01436 /* this signal does one recalc on pose, then unlocks, so ESC or edit will work */ 01437 pose->flag |= POSE_DO_UNLOCK; 01438 01439 /* clear pose if cancelled */ 01440 if (pld->state == PL_PREVIEW_CANCEL) { 01441 poselib_backup_restore(pld); 01442 01443 /* old optimize trick... this enforces to bypass the depgraph 01444 * - note: code copied from transform_generics.c -> recalcData() 01445 */ 01446 if ((arm->flag & ARM_DELAYDEFORM)==0) 01447 DAG_id_tag_update(&ob->id, OB_RECALC_DATA); /* sets recalc flags */ 01448 else 01449 where_is_pose(scene, ob); 01450 01451 } 01452 else if (pld->state == PL_PREVIEW_CONFIRM) { 01453 /* tag poses as appropriate */ 01454 poselib_keytag_pose(C, scene, pld); 01455 01456 /* change active pose setting */ 01457 act->active_marker= BLI_findindex(&act->markers, marker) + 1; 01458 action_set_activemarker(act, marker, NULL); 01459 01460 /* Update event for pose and deformation children */ 01461 DAG_id_tag_update(&ob->id, OB_RECALC_DATA); 01462 01463 /* updates */ 01464 if (IS_AUTOKEY_MODE(scene, NORMAL)) { 01465 //remake_action_ipos(ob->action); 01466 } 01467 else 01468 where_is_pose(scene, ob); 01469 } 01470 01471 /* free memory used for backups and searching */ 01472 poselib_backup_free_data(pld); 01473 BLI_freelistN(&pld->searchp); 01474 01475 /* free temp data for operator */ 01476 MEM_freeN(pld); 01477 op->customdata= NULL; 01478 } 01479 01480 /* End previewing operation */ 01481 static int poselib_preview_exit (bContext *C, wmOperator *op) 01482 { 01483 tPoseLib_PreviewData *pld= op->customdata; 01484 int exit_state = pld->state; 01485 01486 /* finish up */ 01487 poselib_preview_cleanup(C, op); 01488 01489 if (ELEM(exit_state, PL_PREVIEW_CANCEL, PL_PREVIEW_ERROR)) 01490 return OPERATOR_CANCELLED; 01491 else 01492 return OPERATOR_FINISHED; 01493 } 01494 01495 /* Cancel previewing operation (called when exiting Blender) */ 01496 static int poselib_preview_cancel (bContext *C, wmOperator *op) 01497 { 01498 poselib_preview_exit(C, op); 01499 return OPERATOR_CANCELLED; 01500 } 01501 01502 /* main modal status check */ 01503 static int poselib_preview_modal (bContext *C, wmOperator *op, wmEvent *event) 01504 { 01505 tPoseLib_PreviewData *pld= op->customdata; 01506 int ret; 01507 01508 /* 1) check state to see if we're still running */ 01509 if (pld->state != PL_PREVIEW_RUNNING) 01510 return poselib_preview_exit(C, op); 01511 01512 /* 2) handle events */ 01513 ret= poselib_preview_handle_event(C, op, event); 01514 01515 /* 3) apply changes and redraw, otherwise, confirming goes wrong */ 01516 if (pld->redraw) 01517 poselib_preview_apply(C, op); 01518 01519 return ret; 01520 } 01521 01522 /* Modal Operator init */ 01523 static int poselib_preview_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) 01524 { 01525 tPoseLib_PreviewData *pld; 01526 01527 /* check if everything is ok, and init settings for modal operator */ 01528 poselib_preview_init_data(C, op); 01529 pld= (tPoseLib_PreviewData *)op->customdata; 01530 01531 if (pld->state == PL_PREVIEW_ERROR) { 01532 /* an error occurred, so free temp mem used */ 01533 poselib_preview_cleanup(C, op); 01534 return OPERATOR_CANCELLED; 01535 } 01536 01537 /* do initial apply to have something to look at */ 01538 poselib_preview_apply(C, op); 01539 01540 /* add temp handler if we're running as a modal operator */ 01541 WM_event_add_modal_handler(C, op); 01542 01543 return OPERATOR_RUNNING_MODAL; 01544 } 01545 01546 /* Repeat operator */ 01547 static int poselib_preview_exec (bContext *C, wmOperator *op) 01548 { 01549 tPoseLib_PreviewData *pld; 01550 01551 /* check if everything is ok, and init settings for modal operator */ 01552 poselib_preview_init_data(C, op); 01553 pld= (tPoseLib_PreviewData *)op->customdata; 01554 01555 if (pld->state == PL_PREVIEW_ERROR) { 01556 /* an error occurred, so free temp mem used */ 01557 poselib_preview_cleanup(C, op); 01558 return OPERATOR_CANCELLED; 01559 } 01560 01561 /* the exec() callback is effectively a 'run-once' scenario, so set the state to that 01562 * so that everything draws correctly 01563 */ 01564 pld->state = PL_PREVIEW_RUNONCE; 01565 01566 /* apply the active pose */ 01567 poselib_preview_apply(C, op); 01568 01569 /* now, set the status to exit */ 01570 pld->state = PL_PREVIEW_CONFIRM; 01571 01572 /* cleanup */ 01573 return poselib_preview_exit(C, op); 01574 } 01575 01576 void POSELIB_OT_browse_interactive (wmOperatorType *ot) 01577 { 01578 /* identifiers */ 01579 ot->name= "PoseLib Browse Poses"; 01580 ot->idname= "POSELIB_OT_browse_interactive"; 01581 ot->description= "Interactively browse poses in 3D-View"; 01582 01583 /* callbacks */ 01584 ot->invoke= poselib_preview_invoke; 01585 ot->modal= poselib_preview_modal; 01586 ot->cancel= poselib_preview_cancel; 01587 ot->exec= poselib_preview_exec; 01588 ot->poll= has_poselib_pose_data_poll; 01589 01590 /* flags */ 01591 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING; 01592 01593 /* properties */ 01594 // TODO: make the pose_index into a proper enum instead of a cryptic int... 01595 ot->prop= RNA_def_int(ot->srna, "pose_index", -1, -2, INT_MAX, "Pose", "Index of the pose to apply (-2 for no change to pose, -1 for poselib active pose)", 0, INT_MAX); 01596 01597 // XXX: percentage vs factor? 01598 /* not used yet */ 01599 /* RNA_def_float_factor(ot->srna, "blend_factor", 1.0f, 0.0f, 1.0f, "Blend Factor", "Amount that the pose is applied on top of the existing poses", 0.0f, 1.0f); */ 01600 } 01601 01602 void POSELIB_OT_apply_pose (wmOperatorType *ot) 01603 { 01604 /* identifiers */ 01605 ot->name = "Apply Pose Library Pose"; 01606 ot->idname = "POSELIB_OT_apply_pose"; 01607 ot->description = "Apply specified Pose Library pose to the rig"; 01608 01609 /* callbacks */ 01610 ot->exec= poselib_preview_exec; 01611 ot->poll= has_poselib_pose_data_poll; 01612 01613 /* flags */ 01614 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01615 01616 /* properties */ 01617 // TODO: make the pose_index into a proper enum instead of a cryptic int... 01618 ot->prop= RNA_def_int(ot->srna, "pose_index", -1, -2, INT_MAX, "Pose", "Index of the pose to apply (-2 for no change to pose, -1 for poselib active pose)", 0, INT_MAX); 01619 }