'Transform' Python Function for armature, curve and lattice.
[blender.git] / source / blender / editors / armature / armature_edit.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * Contributor(s): Blender Foundation, 2002-2009 full recode.
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  *
25  * Armature EditMode tools - transforms, chain based editing, and other settings
26  */
27
28 /** \file blender/editors/armature/armature_edit.c
29  *  \ingroup edarmature
30  */
31
32 #include <assert.h> 
33
34 #include "DNA_armature_types.h"
35 #include "DNA_constraint_types.h"
36 #include "DNA_object_types.h"
37 #include "DNA_scene_types.h"
38
39 #include "MEM_guardedalloc.h"
40
41 #include "BLI_blenlib.h"
42 #include "BLI_math.h"
43
44 #include "BKE_action.h"
45 #include "BKE_armature.h"
46 #include "BKE_constraint.h"
47 #include "BKE_context.h"
48 #include "BKE_global.h"
49 #include "BKE_report.h"
50
51 #include "RNA_access.h"
52 #include "RNA_define.h"
53
54 #include "WM_api.h"
55 #include "WM_types.h"
56
57 #include "ED_armature.h"
58 #include "ED_screen.h"
59 #include "ED_view3d.h"
60
61 #include "armature_intern.h"
62
63 /* ************************** Object Tools Exports ******************************* */
64 /* NOTE: these functions are exported to the Object module to be called from the tools there */
65
66 void ED_armature_apply_transform(Object *ob, float mat[4][4])
67 {
68         bArmature *arm = ob->data;
69
70         /* Put the armature into editmode */
71         ED_armature_to_edit(arm);
72
73         /* Transform the bones*/
74         ED_armature_transform_bones(arm, mat);
75
76         /* Turn the list into an armature */
77         ED_armature_from_edit(arm);
78         ED_armature_edit_free(arm);
79 }
80
81 void ED_armature_transform_bones(struct bArmature *arm, float mat[4][4])
82 {
83         EditBone *ebone;
84         float scale = mat4_to_scale(mat);   /* store the scale of the matrix here to use on envelopes */
85         float mat3[3][3];
86
87         copy_m3_m4(mat3, mat);
88         normalize_m3(mat3);
89         /* Do the rotations */
90         for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
91                 float tmat[3][3];
92                 
93                 /* find the current bone's roll matrix */
94                 ED_armature_ebone_to_mat3(ebone, tmat);
95                 
96                 /* transform the roll matrix */
97                 mul_m3_m3m3(tmat, mat3, tmat);
98                 
99                 /* transform the bone */
100                 mul_m4_v3(mat, ebone->head);
101                 mul_m4_v3(mat, ebone->tail);
102
103                 /* apply the transfiormed roll back */
104                 mat3_to_vec_roll(tmat, NULL, &ebone->roll);
105                 
106                 ebone->rad_head *= scale;
107                 ebone->rad_tail *= scale;
108                 ebone->dist     *= scale;
109                 
110                 /* we could be smarter and scale by the matrix along the x & z axis */
111                 ebone->xwidth   *= scale;
112                 ebone->zwidth   *= scale;
113         }
114 }
115
116 void ED_armature_transform(struct bArmature *arm, float mat[4][4])
117 {
118         if (arm->edbo) {
119                 ED_armature_transform_bones(arm, mat);
120         }
121         else {
122                 /* Put the armature into editmode */
123                 ED_armature_to_edit(arm);
124
125                 /* Transform the bones */
126                 ED_armature_transform_bones(arm, mat);
127
128                 /* Go back to object mode*/
129                 ED_armature_from_edit(arm);
130                 ED_armature_edit_free(arm);
131         }
132 }
133
134 /* exported for use in editors/object/ */
135 /* 0 == do center, 1 == center new, 2 == center cursor */
136 void ED_armature_origin_set(Scene *scene, Object *ob, float cursor[3], int centermode, int around)
137 {
138         Object *obedit = scene->obedit; // XXX get from context
139         EditBone *ebone;
140         bArmature *arm = ob->data;
141         float cent[3];
142
143         /* Put the armature into editmode */
144         if (ob != obedit) {
145                 ED_armature_to_edit(arm);
146                 obedit = NULL; /* we cant use this so behave as if there is no obedit */
147         }
148
149         /* Find the centerpoint */
150         if (centermode == 2) {
151                 copy_v3_v3(cent, cursor);
152                 invert_m4_m4(ob->imat, ob->obmat);
153                 mul_m4_v3(ob->imat, cent);
154         }
155         else {
156                 if (around == V3D_CENTROID) {
157                         int total = 0;
158                         zero_v3(cent);
159                         for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
160                                 total += 2;
161                                 add_v3_v3(cent, ebone->head);
162                                 add_v3_v3(cent, ebone->tail);
163                         }
164                         if (total) {
165                                 mul_v3_fl(cent, 1.0f / (float)total);
166                         }
167                 }
168                 else {
169                         float min[3], max[3];
170                         INIT_MINMAX(min, max);
171                         for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
172                                 minmax_v3v3_v3(min, max, ebone->head);
173                                 minmax_v3v3_v3(min, max, ebone->tail);
174                         }
175                         mid_v3_v3v3(cent, min, max);
176                 }
177         }
178         
179         /* Do the adjustments */
180         for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
181                 sub_v3_v3(ebone->head, cent);
182                 sub_v3_v3(ebone->tail, cent);
183         }
184         
185         /* Turn the list into an armature */
186         if (obedit == NULL) {
187                 ED_armature_from_edit(arm);
188                 ED_armature_edit_free(arm);
189         }
190
191         /* Adjust object location for new centerpoint */
192         if (centermode && obedit == NULL) {
193                 mul_mat3_m4_v3(ob->obmat, cent); /* ommit translation part */
194                 add_v3_v3(ob->loc, cent);
195         }
196 }
197
198 /* ********************************* Roll ******************************* */
199
200 /* adjust bone roll to align Z axis with vector
201  * vec is in local space and is normalized
202  */
203 float ED_rollBoneToVector(EditBone *bone, const float align_axis[3], const short axis_only)
204 {
205         float mat[3][3], nor[3];
206
207         sub_v3_v3v3(nor, bone->tail, bone->head);
208         vec_roll_to_mat3(nor, 0.0f, mat);
209         
210         /* check the bone isn't aligned with the axis */
211         if (!is_zero_v3(align_axis) && angle_v3v3(align_axis, mat[2]) > FLT_EPSILON) {
212                 float vec[3], align_axis_proj[3], roll;
213                 
214                 /* project the new_up_axis along the normal */
215                 project_v3_v3v3(vec, align_axis, nor);
216                 sub_v3_v3v3(align_axis_proj, align_axis, vec);
217                 
218                 if (axis_only) {
219                         if (angle_v3v3(align_axis_proj, mat[2]) > (float)(M_PI / 2.0)) {
220                                 negate_v3(align_axis_proj);
221                         }
222                 }
223                 
224                 roll = angle_v3v3(align_axis_proj, mat[2]);
225                 
226                 cross_v3_v3v3(vec, mat[2], align_axis_proj);
227                 
228                 if (dot_v3v3(vec, nor) < 0) {
229                         roll = -roll;
230                 }
231                 
232                 return roll;
233         }
234
235         return 0.0f;
236 }
237
238
239 typedef enum eCalcRollTypes {
240         CALC_ROLL_X          = 0,
241         CALC_ROLL_Y          = 1,
242         CALC_ROLL_Z          = 2,
243         
244         CALC_ROLL_ACTIVE     = 5,
245         CALC_ROLL_VIEW       = 6,
246         CALC_ROLL_CURSOR     = 7
247 } eCalcRollTypes;
248
249 static EnumPropertyItem prop_calc_roll_types[] = {
250         {CALC_ROLL_X, "X", 0, "X Axis", ""},
251         {CALC_ROLL_Y, "Y", 0, "Y Axis", ""},
252         {CALC_ROLL_Z, "Z", 0, "Z Axis", ""},
253         {CALC_ROLL_ACTIVE, "ACTIVE", 0, "Active Bone", ""},
254         {CALC_ROLL_VIEW, "VIEW", 0, "View Axis", ""},
255         {CALC_ROLL_CURSOR, "CURSOR", 0, "Cursor", ""},
256         {0, NULL, 0, NULL, NULL}
257 };
258
259
260 static int armature_calc_roll_exec(bContext *C, wmOperator *op) 
261 {
262         Object *ob = CTX_data_edit_object(C);
263         const short type = RNA_enum_get(op->ptr, "type");
264         const short axis_only = RNA_boolean_get(op->ptr, "axis_only");
265         const short axis_flip = RNA_boolean_get(op->ptr, "axis_flip");
266
267         float imat[3][3];
268
269         bArmature *arm = ob->data;
270         EditBone *ebone;
271
272         copy_m3_m4(imat, ob->obmat);
273         invert_m3(imat);
274
275         if (type == CALC_ROLL_CURSOR) { /* Cursor */
276                 Scene *scene = CTX_data_scene(C);
277                 View3D *v3d = CTX_wm_view3d(C); /* can be NULL */
278                 float cursor_local[3];
279                 const float   *cursor = ED_view3d_cursor3d_get(scene, v3d);
280                 
281                 
282                 copy_v3_v3(cursor_local, cursor);
283                 mul_m3_v3(imat, cursor_local);
284                 
285                 /* cursor */
286                 for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
287                         if (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) {
288                                 float cursor_rel[3];
289                                 sub_v3_v3v3(cursor_rel, cursor_local, ebone->head);
290                                 if (axis_flip) negate_v3(cursor_rel);
291                                 ebone->roll = ED_rollBoneToVector(ebone, cursor_rel, axis_only);
292                         }
293                 }
294         }
295         else {
296                 float vec[3] = {0.0f, 0.0f, 0.0f};
297                 if (type == CALC_ROLL_VIEW) { /* View */
298                         RegionView3D *rv3d = CTX_wm_region_view3d(C);
299                         if (rv3d == NULL) {
300                                 BKE_report(op->reports, RPT_ERROR, "No region view3d available");
301                                 return OPERATOR_CANCELLED;
302                         }
303                         
304                         copy_v3_v3(vec, rv3d->viewinv[2]);
305                         mul_m3_v3(imat, vec);
306                 }
307                 else if (type == CALC_ROLL_ACTIVE) {
308                         float mat[3][3];
309                         ebone = (EditBone *)arm->act_edbone;
310                         if (ebone == NULL) {
311                                 BKE_report(op->reports, RPT_ERROR, "No active bone set");
312                                 return OPERATOR_CANCELLED;
313                         }
314                         
315                         ED_armature_ebone_to_mat3(ebone, mat);
316                         copy_v3_v3(vec, mat[2]);
317                 }
318                 else { /* Axis */
319                         assert(type >= 0 && type <= 5);
320                         if (type < 3) vec[type] = 1.0f;
321                         else vec[type - 2] = -1.0f;
322                         mul_m3_v3(imat, vec);
323                 }
324                 
325                 if (axis_flip) negate_v3(vec);
326                 
327                 for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
328                         if (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) {
329                                 /* roll func is a callback which assumes that all is well */
330                                 ebone->roll = ED_rollBoneToVector(ebone, vec, axis_only);
331                         }
332                 }
333         }
334         
335         if (arm->flag & ARM_MIRROR_EDIT) {
336                 for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
337                         if ((EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) == 0) {
338                                 EditBone *ebone_mirr = ED_armature_bone_get_mirrored(arm->edbo, ebone);
339                                 if (ebone_mirr && (EBONE_VISIBLE(arm, ebone_mirr) && EBONE_EDITABLE(ebone_mirr))) {
340                                         ebone->roll = -ebone_mirr->roll;
341                                 }
342                         }
343                 }
344         }
345         
346         /* note, notifier might evolve */
347         WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
348         
349         return OPERATOR_FINISHED;
350 }
351
352 void ARMATURE_OT_calculate_roll(wmOperatorType *ot)
353 {
354         /* identifiers */
355         ot->name = "Recalculate Roll";
356         ot->idname = "ARMATURE_OT_calculate_roll";
357         ot->description = "Automatically fix alignment of select bones' axes";
358         
359         /* api callbacks */
360         ot->invoke = WM_menu_invoke;
361         ot->exec = armature_calc_roll_exec;
362         ot->poll = ED_operator_editarmature;
363         
364         /* flags */
365         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
366
367         /* properties */
368         ot->prop = RNA_def_enum(ot->srna, "type", prop_calc_roll_types, 0, "Type", "");
369         RNA_def_boolean(ot->srna, "axis_flip", 0, "Flip Axis", "Negate the alignment axis");
370         RNA_def_boolean(ot->srna, "axis_only", 0, "Shortest Rotation", "Ignore the axis direction, use the shortest rotation to align");
371 }
372
373 /* ******************************** Chain-Based Tools ********************************* */
374
375 /* temporary data-structure for merge/fill bones */
376 typedef struct EditBonePoint {
377         struct EditBonePoint *next, *prev;
378         
379         EditBone *head_owner;       /* EditBone which uses this point as a 'head' point */
380         EditBone *tail_owner;       /* EditBone which uses this point as a 'tail' point */
381         
382         float vec[3];               /* the actual location of the point in local/EditMode space */
383 } EditBonePoint;
384
385 /* find chain-tips (i.e. bones without children) */
386 static void chains_find_tips(ListBase *edbo, ListBase *list)
387 {
388         EditBone *curBone, *ebo;
389         LinkData *ld;
390         
391         /* note: this is potentially very slow ... there's got to be a better way */
392         for (curBone = edbo->first; curBone; curBone = curBone->next) {
393                 short stop = 0;
394                 
395                 /* is this bone contained within any existing chain? (skip if so) */
396                 for (ld = list->first; ld; ld = ld->next) {
397                         for (ebo = ld->data; ebo; ebo = ebo->parent) {
398                                 if (ebo == curBone) {
399                                         stop = 1;
400                                         break;
401                                 }
402                         }
403                         
404                         if (stop) break;
405                 }
406                 /* skip current bone if it is part of an existing chain */
407                 if (stop) continue;
408                 
409                 /* is any existing chain part of the chain formed by this bone? */
410                 stop = 0;
411                 for (ebo = curBone->parent; ebo; ebo = ebo->parent) {
412                         for (ld = list->first; ld; ld = ld->next) {
413                                 if (ld->data == ebo) {
414                                         ld->data = curBone;
415                                         stop = 1;
416                                         break;
417                                 }
418                         }
419                         
420                         if (stop) break;
421                 }
422                 /* current bone has already been added to a chain? */
423                 if (stop) continue;
424                 
425                 /* add current bone to a new chain */
426                 ld = MEM_callocN(sizeof(LinkData), "BoneChain");
427                 ld->data = curBone;
428                 BLI_addtail(list, ld);
429         }
430 }
431
432 /* --------------------- */
433
434 static void fill_add_joint(EditBone *ebo, short eb_tail, ListBase *points)
435 {
436         EditBonePoint *ebp;
437         float vec[3];
438         short found = 0;
439         
440         if (eb_tail) {
441                 copy_v3_v3(vec, ebo->tail);
442         }
443         else {
444                 copy_v3_v3(vec, ebo->head);
445         }
446         
447         for (ebp = points->first; ebp; ebp = ebp->next) {
448                 if (equals_v3v3(ebp->vec, vec)) {
449                         if (eb_tail) {
450                                 if ((ebp->head_owner) && (ebp->head_owner->parent == ebo)) {
451                                         /* so this bone's tail owner is this bone */
452                                         ebp->tail_owner = ebo;
453                                         found = 1;
454                                         break;
455                                 }
456                         }
457                         else {
458                                 if ((ebp->tail_owner) && (ebo->parent == ebp->tail_owner)) {
459                                         /* so this bone's head owner is this bone */
460                                         ebp->head_owner = ebo;
461                                         found = 1;
462                                         break;
463                                 }
464                         }
465                 }
466         }
467         
468         /* allocate a new point if no existing point was related */
469         if (found == 0) {
470                 ebp = MEM_callocN(sizeof(EditBonePoint), "EditBonePoint");
471                 
472                 if (eb_tail) {
473                         copy_v3_v3(ebp->vec, ebo->tail);
474                         ebp->tail_owner = ebo;
475                 }
476                 else {
477                         copy_v3_v3(ebp->vec, ebo->head);
478                         ebp->head_owner = ebo;
479                 }
480                 
481                 BLI_addtail(points, ebp);
482         }
483 }
484
485 /* bone adding between selected joints */
486 static int armature_fill_bones_exec(bContext *C, wmOperator *op)
487 {
488         Object *obedit = CTX_data_edit_object(C);
489         bArmature *arm = (obedit) ? obedit->data : NULL;
490         Scene *scene = CTX_data_scene(C);
491         View3D *v3d = CTX_wm_view3d(C);
492         ListBase points = {NULL, NULL};
493         int count;
494
495         /* sanity checks */
496         if (ELEM(NULL, obedit, arm))
497                 return OPERATOR_CANCELLED;
498
499         /* loop over all bones, and only consider if visible */
500         CTX_DATA_BEGIN(C, EditBone *, ebone, visible_bones)
501         {
502                 if (!(ebone->flag & BONE_CONNECTED) && (ebone->flag & BONE_ROOTSEL))
503                         fill_add_joint(ebone, 0, &points);
504                 if (ebone->flag & BONE_TIPSEL) 
505                         fill_add_joint(ebone, 1, &points);
506         }
507         CTX_DATA_END;
508         
509         /* the number of joints determines how we fill:
510          *  1) between joint and cursor (joint=head, cursor=tail)
511          *  2) between the two joints (order is dependent on active-bone/hierarchy)
512          *  3+) error (a smarter method involving finding chains needs to be worked out
513          */
514         count = BLI_countlist(&points);
515         
516         if (count == 0) {
517                 BKE_report(op->reports, RPT_ERROR, "No joints selected");
518                 return OPERATOR_CANCELLED;
519         }
520         else if (count == 1) {
521                 EditBonePoint *ebp;
522                 float curs[3];
523                 
524                 /* Get Points - selected joint */
525                 ebp = (EditBonePoint *)points.first;
526                 
527                 /* Get points - cursor (tail) */
528                 invert_m4_m4(obedit->imat, obedit->obmat);
529                 mul_v3_m4v3(curs, obedit->imat, ED_view3d_cursor3d_get(scene, v3d));
530                 
531                 /* Create a bone */
532                 /* newbone = */ add_points_bone(obedit, ebp->vec, curs);
533         }
534         else if (count == 2) {
535                 EditBonePoint *ebp, *ebp2;
536                 float head[3], tail[3];
537                 short headtail = 0;
538                 
539                 /* check that the points don't belong to the same bone */
540                 ebp = (EditBonePoint *)points.first;
541                 ebp2 = ebp->next;
542                 
543                 if ((ebp->head_owner == ebp2->tail_owner) && (ebp->head_owner != NULL)) {
544                         BKE_report(op->reports, RPT_ERROR, "Same bone selected...");
545                         BLI_freelistN(&points);
546                         return OPERATOR_CANCELLED;
547                 }
548                 if ((ebp->tail_owner == ebp2->head_owner) && (ebp->tail_owner != NULL)) {
549                         BKE_report(op->reports, RPT_ERROR, "Same bone selected...");
550                         BLI_freelistN(&points);
551                         return OPERATOR_CANCELLED;
552                 }
553                 
554                 /* find which one should be the 'head' */
555                 if ((ebp->head_owner && ebp2->head_owner) || (ebp->tail_owner && ebp2->tail_owner)) {
556                         /* rule: whichever one is closer to 3d-cursor */
557                         float curs[3];
558                         float vecA[3], vecB[3];
559                         float distA, distB;
560                         
561                         /* get cursor location */
562                         invert_m4_m4(obedit->imat, obedit->obmat);
563                         mul_v3_m4v3(curs, obedit->imat, ED_view3d_cursor3d_get(scene, v3d));
564                         
565                         /* get distances */
566                         sub_v3_v3v3(vecA, ebp->vec, curs);
567                         sub_v3_v3v3(vecB, ebp2->vec, curs);
568                         distA = len_v3(vecA);
569                         distB = len_v3(vecB);
570                         
571                         /* compare distances - closer one therefore acts as direction for bone to go */
572                         headtail = (distA < distB) ? 2 : 1;
573                 }
574                 else if (ebp->head_owner) {
575                         headtail = 1;
576                 }
577                 else if (ebp2->head_owner) {
578                         headtail = 2;
579                 }
580                 
581                 /* assign head/tail combinations */
582                 if (headtail == 2) {
583                         copy_v3_v3(head, ebp->vec);
584                         copy_v3_v3(tail, ebp2->vec);
585                 }
586                 else if (headtail == 1) {
587                         copy_v3_v3(head, ebp2->vec);
588                         copy_v3_v3(tail, ebp->vec);
589                 }
590                 
591                 /* add new bone and parent it to the appropriate end */
592                 if (headtail) {
593                         EditBone *newbone = add_points_bone(obedit, head, tail);
594                         
595                         /* do parenting (will need to set connected flag too) */
596                         if (headtail == 2) {
597                                 /* ebp tail or head - tail gets priority */
598                                 if (ebp->tail_owner)
599                                         newbone->parent = ebp->tail_owner;
600                                 else
601                                         newbone->parent = ebp->head_owner;
602                         }
603                         else {
604                                 /* ebp2 tail or head - tail gets priority */
605                                 if (ebp2->tail_owner)
606                                         newbone->parent = ebp2->tail_owner;
607                                 else
608                                         newbone->parent = ebp2->head_owner;
609                         }
610
611                         /* don't set for bone connecting two head points of bones */
612                         if (ebp->tail_owner || ebp2->tail_owner) {
613                                 newbone->flag |= BONE_CONNECTED;
614                         }
615                 }
616         }
617         else {
618                 /* FIXME.. figure out a method for multiple bones */
619                 BKE_reportf(op->reports, RPT_ERROR, "Too many points selected: %d", count);
620                 BLI_freelistN(&points);
621                 return OPERATOR_CANCELLED;
622         }
623         
624         /* updates */
625         WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit);
626         
627         /* free points */
628         BLI_freelistN(&points);
629         
630         return OPERATOR_FINISHED;
631 }
632
633 void ARMATURE_OT_fill(wmOperatorType *ot)
634 {
635         /* identifiers */
636         ot->name = "Fill Between Joints";
637         ot->idname = "ARMATURE_OT_fill";
638         ot->description = "Add bone between selected joint(s) and/or 3D-Cursor";
639         
640         /* callbacks */
641         ot->exec = armature_fill_bones_exec;
642         ot->poll = ED_operator_editarmature;
643         
644         /* flags */
645         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
646 }
647
648 /* --------------------- */
649
650 /* this function merges between two bones, removes them and those in-between, 
651  * and adjusts the parent relationships for those in-between
652  */
653 static void bones_merge(Object *obedit, EditBone *start, EditBone *end, EditBone *endchild, ListBase *chains)
654 {
655         bArmature *arm = obedit->data;
656         EditBone *ebo, *ebone, *newbone;
657         LinkData *chain;
658         float head[3], tail[3];
659         
660         /* check if same bone */
661         if (start == end) {
662                 if (G.debug & G_DEBUG) {
663                         printf("Error: same bone!\n");
664                         printf("\tstart = %s, end = %s\n", start->name, end->name);
665                 }
666         }
667         
668         /* step 1: add a new bone
669          *      - head = head/tail of start (default head)
670          *      - tail = head/tail of end (default tail)
671          *      - parent = parent of start
672          */
673         if ((start->flag & BONE_TIPSEL) && (start->flag & BONE_SELECTED) == 0) {
674                 copy_v3_v3(head, start->tail);
675         }
676         else {
677                 copy_v3_v3(head, start->head);
678         }
679         if ((end->flag & BONE_ROOTSEL) && (end->flag & BONE_SELECTED) == 0) {
680                 copy_v3_v3(tail, end->head);
681         }
682         else {
683                 copy_v3_v3(tail, end->tail);
684         }
685         newbone = add_points_bone(obedit, head, tail);
686         newbone->parent = start->parent;
687
688         /* TODO, copy more things to the new bone */
689         newbone->flag = start->flag & (BONE_HINGE | BONE_NO_DEFORM | BONE_NO_SCALE |
690                                        BONE_NO_CYCLICOFFSET | BONE_NO_LOCAL_LOCATION | BONE_DONE);
691         
692         /* step 2a: reparent any side chains which may be parented to any bone in the chain of bones to merge 
693          *      - potentially several tips for side chains leading to some tree exist...
694          */
695         for (chain = chains->first; chain; chain = chain->next) {
696                 /* traverse down chain until we hit the bottom or if we run into the tip of the chain of bones we're 
697                  * merging (need to stop in this case to avoid corrupting this chain too!) 
698                  */
699                 for (ebone = chain->data; (ebone) && (ebone != end); ebone = ebone->parent) {
700                         short found = 0;
701                         
702                         /* check if this bone is parented to one in the merging chain
703                          * ! WATCHIT: must only go check until end of checking chain
704                          */
705                         for (ebo = end; (ebo) && (ebo != start->parent); ebo = ebo->parent) {
706                                 /* side-chain found? --> remap parent to new bone, then we're done with this chain :) */
707                                 if (ebone->parent == ebo) {
708                                         ebone->parent = newbone;
709                                         found = 1;
710                                         break;
711                                 }
712                         }
713                         
714                         /* carry on to the next tip now  */
715                         if (found) 
716                                 break;
717                 }
718         }
719         
720         /* step 2b: parent child of end to newbone (child from this chain) */
721         if (endchild)
722                 endchild->parent = newbone;
723         
724         /* step 3: delete all bones between and including start and end */
725         for (ebo = end; ebo; ebo = ebone) {
726                 ebone = (ebo == start) ? (NULL) : (ebo->parent);
727                 bone_free(arm, ebo);
728         }
729         
730         newbone->flag |= (BONE_ROOTSEL | BONE_TIPSEL | BONE_SELECTED);
731         ED_armature_sync_selection(arm->edbo);
732 }
733
734
735 static int armature_merge_exec(bContext *C, wmOperator *op)
736 {
737         Object *obedit = CTX_data_edit_object(C);
738         bArmature *arm = (obedit) ? obedit->data : NULL;
739         short type = RNA_enum_get(op->ptr, "type");
740         
741         /* sanity checks */
742         if (ELEM(NULL, obedit, arm))
743                 return OPERATOR_CANCELLED;
744         
745         /* for now, there's only really one type of merging that's performed... */
746         if (type == 1) {
747                 /* go down chains, merging bones */
748                 ListBase chains = {NULL, NULL};
749                 LinkData *chain, *nchain;
750                 EditBone *ebo;
751                 
752                 armature_tag_select_mirrored(arm);
753                 
754                 /* get chains (ends on chains) */
755                 chains_find_tips(arm->edbo, &chains);
756                 if (chains.first == NULL) return OPERATOR_CANCELLED;
757                 
758                 /* each 'chain' is the last bone in the chain (with no children) */
759                 for (chain = chains.first; chain; chain = nchain) {
760                         EditBone *bstart = NULL, *bend = NULL;
761                         EditBone *bchild = NULL, *child = NULL;
762                         
763                         /* temporarily remove chain from list of chains */
764                         nchain = chain->next;
765                         BLI_remlink(&chains, chain);
766                         
767                         /* only consider bones that are visible and selected */
768                         for (ebo = chain->data; ebo; child = ebo, ebo = ebo->parent) {
769                                 /* check if visible + selected */
770                                 if (EBONE_VISIBLE(arm, ebo) &&
771                                     ((ebo->flag & BONE_CONNECTED) || (ebo->parent == NULL)) &&
772                                     (ebo->flag & BONE_SELECTED) )
773                                 {
774                                         /* set either end or start (end gets priority, unless it is already set) */
775                                         if (bend == NULL) {
776                                                 bend = ebo;
777                                                 bchild = child;
778                                         }
779                                         else 
780                                                 bstart = ebo;
781                                 }
782                                 else {
783                                         /* chain is broken... merge any continous segments then clear */
784                                         if (bstart && bend)
785                                                 bones_merge(obedit, bstart, bend, bchild, &chains);
786                                         
787                                         bstart = NULL;
788                                         bend = NULL;
789                                         bchild = NULL;
790                                 }
791                         }
792                         
793                         /* merge from bstart to bend if something not merged */
794                         if (bstart && bend)
795                                 bones_merge(obedit, bstart, bend, bchild, &chains);
796                         
797                         /* put back link */
798                         BLI_insertlinkbefore(&chains, nchain, chain);
799                 }
800                 
801                 armature_tag_unselect(arm);
802                 
803                 BLI_freelistN(&chains);
804         }
805         
806         /* updates */
807         ED_armature_sync_selection(arm->edbo);
808         WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit);
809         
810         return OPERATOR_FINISHED;
811 }
812
813 void ARMATURE_OT_merge(wmOperatorType *ot)
814 {
815         static EnumPropertyItem merge_types[] = {
816                 {1, "WITHIN_CHAIN", 0, "Within Chains", ""},
817                 {0, NULL, 0, NULL, NULL}
818         };
819
820         /* identifiers */
821         ot->name = "Merge Bones";
822         ot->idname = "ARMATURE_OT_merge";
823         ot->description = "Merge continuous chains of selected bones";
824         
825         /* callbacks */
826         ot->invoke = WM_menu_invoke;
827         ot->exec = armature_merge_exec;
828         ot->poll = ED_operator_editarmature;
829         
830         /* flags */
831         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
832         
833         /* properties */
834         ot->prop = RNA_def_enum(ot->srna, "type", merge_types, 0, "Type", "");
835 }
836
837 /* --------------------- */
838
839 /* Switch Direction operator:
840  * Currently, this does not use context loops, as context loops do not make it
841  * easy to retrieve any hierarchical/chain relationships which are necessary for
842  * this to be done easily.
843  */
844  
845 /* helper to clear BONE_TRANSFORM flags */
846 static void armature_clear_swap_done_flags(bArmature *arm)
847 {
848         EditBone *ebone;
849         
850         for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
851                 ebone->flag &= ~BONE_TRANSFORM;
852         }
853 }
854
855 static int armature_switch_direction_exec(bContext *C, wmOperator *UNUSED(op)) 
856 {
857         Object *ob = CTX_data_edit_object(C);
858         bArmature *arm = (bArmature *)ob->data;
859         ListBase chains = {NULL, NULL};
860         LinkData *chain;
861         
862         /* get chains of bones (ends on chains) */
863         chains_find_tips(arm->edbo, &chains);
864         if (chains.first == NULL) return OPERATOR_CANCELLED;
865         
866         /* ensure that mirror bones will also be operated on */
867         armature_tag_select_mirrored(arm);
868         
869         /* clear BONE_TRANSFORM flags 
870          * - used to prevent duplicate/canceling operations from occurring [#34123]
871          * - BONE_DONE cannot be used here as that's already used for mirroring
872          */
873         armature_clear_swap_done_flags(arm);
874         
875         /* loop over chains, only considering selected and visible bones */
876         for (chain = chains.first; chain; chain = chain->next) {
877                 EditBone *ebo, *child = NULL, *parent = NULL;
878                 
879                 /* loop over bones in chain */
880                 for (ebo = chain->data; ebo; ebo = parent) {
881                         /* parent is this bone's original parent
882                          *      - we store this, as the next bone that is checked is this one
883                          *        but the value of ebo->parent may change here...
884                          */
885                         parent = ebo->parent;
886                         
887                         /* skip bone if already handled... [#34123] */
888                         if ((ebo->flag & BONE_TRANSFORM) == 0) {
889                                 /* only if selected and editable */
890                                 if (EBONE_VISIBLE(arm, ebo) && EBONE_EDITABLE(ebo)) {
891                                         /* swap head and tail coordinates */
892                                         SWAP(float, ebo->head[0], ebo->tail[0]);
893                                         SWAP(float, ebo->head[1], ebo->tail[1]);
894                                         SWAP(float, ebo->head[2], ebo->tail[2]);
895                                         
896                                         /* do parent swapping:
897                                          *      - use 'child' as new parent
898                                          *      - connected flag is only set if points are coincidental
899                                          */
900                                         ebo->parent = child;
901                                         if ((child) && equals_v3v3(ebo->head, child->tail))
902                                                 ebo->flag |= BONE_CONNECTED;
903                                         else
904                                                 ebo->flag &= ~BONE_CONNECTED;
905                                         
906                                         /* get next bones 
907                                          *      - child will become the new parent of next bone
908                                          */
909                                         child = ebo;
910                                 }
911                                 else {
912                                         /* not swapping this bone, however, if its 'parent' got swapped, unparent us from it 
913                                          * as it will be facing in opposite direction
914                                          */
915                                         if ((parent) && (EBONE_VISIBLE(arm, parent) && EBONE_EDITABLE(parent))) {
916                                                 ebo->parent = NULL;
917                                                 ebo->flag &= ~BONE_CONNECTED;
918                                         }
919                                         
920                                         /* get next bones
921                                          *      - child will become new parent of next bone (not swapping occurred, 
922                                          *        so set to NULL to prevent infinite-loop)
923                                          */
924                                         child = NULL;
925                                 }
926                                 
927                                 /* tag as done (to prevent double-swaps) */
928                                 ebo->flag |= BONE_TRANSFORM;
929                         }
930                 }
931         }
932         
933         /* free chains */
934         BLI_freelistN(&chains);
935         
936         /* clear temp flags */
937         armature_clear_swap_done_flags(arm);
938         armature_tag_unselect(arm);
939         
940         /* note, notifier might evolve */
941         WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
942         
943         return OPERATOR_FINISHED;
944 }
945
946 void ARMATURE_OT_switch_direction(wmOperatorType *ot)
947 {
948         /* identifiers */
949         ot->name = "Switch Direction";
950         ot->idname = "ARMATURE_OT_switch_direction";
951         ot->description = "Change the direction that a chain of bones points in (head <-> tail swap)";
952         
953         /* api callbacks */
954         ot->exec = armature_switch_direction_exec;
955         ot->poll = ED_operator_editarmature;
956         
957         /* flags */
958         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
959 }
960
961 /* ********************************* Align ******************************* */
962
963 /* helper to fix a ebone position if its parent has moved due to alignment*/
964 static void fix_connected_bone(EditBone *ebone)
965 {
966         float diff[3];
967         
968         if (!(ebone->parent) || !(ebone->flag & BONE_CONNECTED) || equals_v3v3(ebone->parent->tail, ebone->head))
969                 return;
970         
971         /* if the parent has moved we translate child's head and tail accordingly */
972         sub_v3_v3v3(diff, ebone->parent->tail, ebone->head);
973         add_v3_v3(ebone->head, diff);
974         add_v3_v3(ebone->tail, diff);
975 }
976
977 /* helper to recursively find chains of connected bones starting at ebone and fix their position */
978 static void fix_editbone_connected_children(ListBase *edbo, EditBone *ebone)
979 {
980         EditBone *selbone;
981         
982         for (selbone = edbo->first; selbone; selbone = selbone->next) {
983                 if ((selbone->parent) && (selbone->parent == ebone) && (selbone->flag & BONE_CONNECTED)) {
984                         fix_connected_bone(selbone);
985                         fix_editbone_connected_children(edbo, selbone);
986                 }
987         }
988 }                       
989
990 static void bone_align_to_bone(ListBase *edbo, EditBone *selbone, EditBone *actbone)
991 {
992         float selboneaxis[3], actboneaxis[3], length;
993
994         sub_v3_v3v3(actboneaxis, actbone->tail, actbone->head);
995         normalize_v3(actboneaxis);
996
997         sub_v3_v3v3(selboneaxis, selbone->tail, selbone->head);
998         length =  len_v3(selboneaxis);
999
1000         mul_v3_fl(actboneaxis, length);
1001         add_v3_v3v3(selbone->tail, selbone->head, actboneaxis);
1002         selbone->roll = actbone->roll;
1003         
1004         /* if the bone being aligned has connected descendants they must be moved
1005          * according to their parent new position, otherwise they would be left
1006          * in an inconsistent state: connected but away from the parent*/
1007         fix_editbone_connected_children(edbo, selbone);
1008 }
1009
1010 static int armature_align_bones_exec(bContext *C, wmOperator *op) 
1011 {
1012         Object *ob = CTX_data_edit_object(C);
1013         bArmature *arm = (bArmature *)ob->data;
1014         EditBone *actbone = CTX_data_active_bone(C);
1015         EditBone *actmirb = NULL;
1016         int num_selected_bones;
1017         
1018         /* there must be an active bone */
1019         if (actbone == NULL) {
1020                 BKE_report(op->reports, RPT_ERROR, "Operation requires an active bone");
1021                 return OPERATOR_CANCELLED;
1022         }
1023         else if (arm->flag & ARM_MIRROR_EDIT) {
1024                 /* For X-Axis Mirror Editing option, we may need a mirror copy of actbone
1025                  * - if there's a mirrored copy of selbone, try to find a mirrored copy of actbone 
1026                  *   (i.e.  selbone="child.L" and actbone="parent.L", find "child.R" and "parent.R").
1027                  *   This is useful for arm-chains, for example parenting lower arm to upper arm
1028                  * - if there's no mirrored copy of actbone (i.e. actbone = "parent.C" or "parent")
1029                  *   then just use actbone. Useful when doing upper arm to spine.
1030                  */
1031                 actmirb = ED_armature_bone_get_mirrored(arm->edbo, actbone);
1032                 if (actmirb == NULL) 
1033                         actmirb = actbone;
1034         }
1035         
1036         /* if there is only 1 selected bone, we assume that that is the active bone, 
1037          * since a user will need to have clicked on a bone (thus selecting it) to make it active
1038          */
1039         num_selected_bones = CTX_DATA_COUNT(C, selected_editable_bones);
1040         if (num_selected_bones <= 1) {
1041                 /* When only the active bone is selected, and it has a parent,
1042                  * align it to the parent, as that is the only possible outcome. 
1043                  */
1044                 if (actbone->parent) {
1045                         bone_align_to_bone(arm->edbo, actbone, actbone->parent);
1046                         
1047                         if ((arm->flag & ARM_MIRROR_EDIT) && (actmirb->parent))
1048                                 bone_align_to_bone(arm->edbo, actmirb, actmirb->parent);
1049
1050                         BKE_reportf(op->reports, RPT_INFO, "Aligned bone '%s' to parent", actbone->name);
1051                 }
1052         }
1053         else {
1054                 /* Align 'selected' bones to the active one
1055                  * - the context iterator contains both selected bones and their mirrored copies,
1056                  *   so we assume that unselected bones are mirrored copies of some selected bone
1057                  * - since the active one (and/or its mirror) will also be selected, we also need 
1058                  *   to check that we are not trying to operate on them, since such an operation
1059                  *   would cause errors
1060                  */
1061                 
1062                 /* align selected bones to the active one */
1063                 CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones)
1064                 {
1065                         if (ELEM(ebone, actbone, actmirb) == 0) {
1066                                 if (ebone->flag & BONE_SELECTED)
1067                                         bone_align_to_bone(arm->edbo, ebone, actbone);
1068                                 else
1069                                         bone_align_to_bone(arm->edbo, ebone, actmirb);
1070                         }
1071                 }
1072                 CTX_DATA_END;
1073
1074                 BKE_reportf(op->reports, RPT_INFO, "%d bones aligned to bone '%s'", num_selected_bones, actbone->name);
1075         }
1076
1077         /* note, notifier might evolve */
1078         WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob);
1079         
1080         return OPERATOR_FINISHED;
1081 }
1082
1083 void ARMATURE_OT_align(wmOperatorType *ot)
1084 {
1085         /* identifiers */
1086         ot->name = "Align Bones";
1087         ot->idname = "ARMATURE_OT_align";
1088         ot->description = "Align selected bones to the active bone (or to their parent)";
1089         
1090         /* api callbacks */
1091         ot->exec = armature_align_bones_exec;
1092         ot->poll = ED_operator_editarmature;
1093         
1094         /* flags */
1095         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1096 }
1097
1098 /* ********************************* Split ******************************* */
1099
1100 static int armature_split_exec(bContext *C, wmOperator *UNUSED(op))
1101 {
1102         Object *ob = CTX_data_edit_object(C);
1103         bArmature *arm = (bArmature *)ob->data;
1104         EditBone *bone;
1105
1106         for (bone = arm->edbo->first; bone; bone = bone->next) {
1107                 if (bone->parent && (bone->flag & BONE_SELECTED) != (bone->parent->flag & BONE_SELECTED)) {
1108                         bone->parent = NULL;
1109                         bone->flag &= ~BONE_CONNECTED;
1110                 }
1111         }
1112         for (bone = arm->edbo->first; bone; bone = bone->next) {
1113                 ED_armature_ebone_select_set(bone, (bone->flag & BONE_SELECTED) != 0);
1114         }
1115
1116         WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
1117
1118         return OPERATOR_FINISHED;
1119 }
1120
1121 void ARMATURE_OT_split(wmOperatorType *ot)
1122 {
1123         /* identifiers */
1124         ot->name = "Split";
1125         ot->idname = "ARMATURE_OT_split";
1126         ot->description = "Split off selected bones from connected unselected bones";
1127
1128         /* api callbacks */
1129         ot->exec = armature_split_exec;
1130         ot->poll = ED_operator_editarmature;
1131
1132         /* flags */
1133         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1134 }
1135
1136 /* ********************************* Delete ******************************* */
1137
1138 /* previously delete_armature */
1139 /* only editmode! */
1140 static int armature_delete_selected_exec(bContext *C, wmOperator *op)
1141 {
1142         bArmature *arm;
1143         EditBone *curBone, *ebone_next;
1144         bConstraint *con;
1145         Object *obedit = CTX_data_edit_object(C); // XXX get from context
1146         int num_deleted = 0;
1147         arm = obedit->data;
1148
1149         /* cancel if nothing selected */
1150         if (CTX_DATA_COUNT(C, selected_bones) == 0)
1151                 return OPERATOR_CANCELLED;
1152         
1153         armature_select_mirrored(arm);
1154         
1155         /*  First erase any associated pose channel */
1156         if (obedit->pose) {
1157                 bPoseChannel *pchan, *pchan_next;
1158                 for (pchan = obedit->pose->chanbase.first; pchan; pchan = pchan_next) {
1159                         pchan_next = pchan->next;
1160                         curBone = ED_armature_bone_find_name(arm->edbo, pchan->name);
1161                         
1162                         if (curBone && (curBone->flag & BONE_SELECTED) && (arm->layer & curBone->layer)) {
1163                                 BKE_pose_channel_free(pchan);
1164                                 BKE_pose_channels_hash_free(obedit->pose);
1165                                 BLI_freelinkN(&obedit->pose->chanbase, pchan);
1166                         }
1167                         else {
1168                                 for (con = pchan->constraints.first; con; con = con->next) {
1169                                         bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con);
1170                                         ListBase targets = {NULL, NULL};
1171                                         bConstraintTarget *ct;
1172                                         
1173                                         if (cti && cti->get_constraint_targets) {
1174                                                 cti->get_constraint_targets(con, &targets);
1175                                                 
1176                                                 for (ct = targets.first; ct; ct = ct->next) {
1177                                                         if (ct->tar == obedit) {
1178                                                                 if (ct->subtarget[0]) {
1179                                                                         curBone = ED_armature_bone_find_name(arm->edbo, ct->subtarget);
1180                                                                         if (curBone && (curBone->flag & BONE_SELECTED) && (arm->layer & curBone->layer)) {
1181                                                                                 con->flag |= CONSTRAINT_DISABLE;
1182                                                                                 ct->subtarget[0] = 0;
1183                                                                         }
1184                                                                 }
1185                                                         }
1186                                                 }
1187                                                 
1188                                                 if (cti->flush_constraint_targets)
1189                                                         cti->flush_constraint_targets(con, &targets, 0);
1190                                         }
1191                                 }
1192                         }
1193                 }
1194         }
1195         
1196         
1197         for (curBone = arm->edbo->first; curBone; curBone = ebone_next) {
1198                 ebone_next = curBone->next;
1199                 if (arm->layer & curBone->layer) {
1200                         if (curBone->flag & BONE_SELECTED) {
1201                                 if (curBone == arm->act_edbone) arm->act_edbone = NULL;
1202                                 ED_armature_edit_bone_remove(arm, curBone);
1203                                 num_deleted++;
1204                         }
1205                 }
1206         }
1207         
1208         BKE_reportf(op->reports, RPT_INFO, "Deleted %d bones", num_deleted);
1209         
1210         ED_armature_sync_selection(arm->edbo);
1211
1212         WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
1213
1214         return OPERATOR_FINISHED;
1215 }
1216
1217 void ARMATURE_OT_delete(wmOperatorType *ot)
1218 {
1219         /* identifiers */
1220         ot->name = "Delete Selected Bone(s)";
1221         ot->idname = "ARMATURE_OT_delete";
1222         ot->description = "Remove selected bones from the armature";
1223         
1224         /* api callbacks */
1225         ot->exec = armature_delete_selected_exec;
1226         ot->poll = ED_operator_editarmature;
1227         
1228         /* flags */
1229         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1230 }
1231
1232 /* ********************************* Show/Hide ******************************* */
1233
1234 static int armature_hide_exec(bContext *C, wmOperator *op)
1235 {
1236         Object *obedit = CTX_data_edit_object(C);
1237         bArmature *arm = obedit->data;
1238         EditBone *ebone;
1239         const int invert = RNA_boolean_get(op->ptr, "unselected") ? BONE_SELECTED : 0;
1240
1241         /* cancel if nothing selected */
1242         if (CTX_DATA_COUNT(C, selected_bones) == 0)
1243                 return OPERATOR_CANCELLED;
1244
1245         for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
1246                 if (EBONE_VISIBLE(arm, ebone)) {
1247                         if ((ebone->flag & BONE_SELECTED) != invert) {
1248                                 ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
1249                                 ebone->flag |= BONE_HIDDEN_A;
1250                         }
1251                 }
1252         }
1253         ED_armature_validate_active(arm);
1254         ED_armature_sync_selection(arm->edbo);
1255
1256         WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
1257
1258         return OPERATOR_FINISHED;
1259 }
1260
1261 void ARMATURE_OT_hide(wmOperatorType *ot)
1262 {
1263         /* identifiers */
1264         ot->name = "Hide Selected Bones";
1265         ot->idname = "ARMATURE_OT_hide";
1266         ot->description = "Tag selected bones to not be visible in Edit Mode";
1267         
1268         /* api callbacks */
1269         ot->exec = armature_hide_exec;
1270         ot->poll = ED_operator_editarmature;
1271         
1272         /* flags */
1273         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1274
1275         /* props */
1276         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected");
1277 }
1278
1279 static int armature_reveal_exec(bContext *C, wmOperator *UNUSED(op))
1280 {
1281         Object *obedit = CTX_data_edit_object(C);
1282         bArmature *arm = obedit->data;
1283         EditBone *ebone;
1284         
1285         for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
1286                 if (arm->layer & ebone->layer) {
1287                         if (ebone->flag & BONE_HIDDEN_A) {
1288                                 ebone->flag |= (BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
1289                                 ebone->flag &= ~BONE_HIDDEN_A;
1290                         }
1291                 }
1292         }
1293         ED_armature_validate_active(arm);
1294         ED_armature_sync_selection(arm->edbo);
1295
1296         WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
1297
1298         return OPERATOR_FINISHED;
1299 }
1300
1301 void ARMATURE_OT_reveal(wmOperatorType *ot)
1302 {
1303         /* identifiers */
1304         ot->name = "Reveal Bones";
1305         ot->idname = "ARMATURE_OT_reveal";
1306         ot->description = "Unhide all bones that have been tagged to be hidden in Edit Mode";
1307         
1308         /* api callbacks */
1309         ot->exec = armature_reveal_exec;
1310         ot->poll = ED_operator_editarmature;
1311         
1312         /* flags */
1313         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1314
1315 }