svn merge ^/trunk/blender -r48321:48333
[blender.git] / source / blender / editors / transform / transform_orientations.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  * Contributor(s): Martin Poirier
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 /** \file blender/editors/transform/transform_orientations.c
24  *  \ingroup edtransform
25  */
26
27
28 #include <string.h>
29 #include <ctype.h>
30
31 #include "MEM_guardedalloc.h"
32
33 #include "DNA_armature_types.h"
34 #include "DNA_curve_types.h"
35 #include "DNA_mesh_types.h"
36 #include "DNA_object_types.h"
37 #include "DNA_scene_types.h"
38 #include "DNA_screen_types.h"
39 #include "DNA_view3d_types.h"
40
41 #include "BLI_math.h"
42 #include "BLI_blenlib.h"
43 #include "BLI_utildefines.h"
44
45 #include "BKE_armature.h"
46 #include "BKE_curve.h"
47 #include "BKE_context.h"
48 #include "BKE_tessmesh.h"
49 #include "BKE_report.h"
50
51 #include "BLF_translation.h"
52
53 //#include "BIF_editmesh.h"
54 //#include "BIF_interface.h"
55 //#include "BIF_space.h"
56 //#include "BIF_toolbox.h"
57
58 #include "ED_armature.h"
59 #include "ED_mesh.h"
60
61 #include "RNA_define.h"
62
63 #include "UI_interface.h"
64
65 #include "transform.h"
66
67 /* *********************** TransSpace ************************** */
68
69 void BIF_clearTransformOrientation(bContext *C)
70 {
71         View3D *v3d = CTX_wm_view3d(C);
72
73         ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
74         BLI_freelistN(transform_spaces);
75         
76         // Need to loop over all view3d
77         if (v3d && v3d->twmode >= V3D_MANIP_CUSTOM) {
78                 v3d->twmode = V3D_MANIP_GLOBAL; /* fallback to global   */
79         }
80 }
81
82 static TransformOrientation *findOrientationName(ListBase *lb, const char *name)
83 {
84         TransformOrientation *ts = NULL;
85
86         for (ts = lb->first; ts; ts = ts->next) {
87                 if (strncmp(ts->name, name, sizeof(ts->name) - 1) == 0) {
88                         return ts;
89                 }
90         }
91         
92         return NULL;
93 }
94
95 static int uniqueOrientationNameCheck(void *arg, const char *name)
96 {
97         return findOrientationName((ListBase *)arg, name) != NULL;
98 }
99
100 static void uniqueOrientationName(ListBase *lb, char *name)
101 {
102         BLI_uniquename_cb(uniqueOrientationNameCheck, lb, "Space", '.', name, sizeof(((TransformOrientation *)NULL)->name));
103 }
104
105 void BIF_createTransformOrientation(bContext *C, ReportList *reports, char *name, int use, int overwrite)
106 {
107         Object *obedit = CTX_data_edit_object(C);
108         Object *ob = CTX_data_active_object(C);
109         TransformOrientation *ts = NULL;
110         
111         if (obedit) {
112                 if (obedit->type == OB_MESH)
113                         ts = createMeshSpace(C, reports, name, overwrite);
114                 else if (obedit->type == OB_ARMATURE)
115                         ts = createBoneSpace(C, reports, name, overwrite);
116         }
117         else if (ob && (ob->mode & OB_MODE_POSE)) {
118                 ts = createBoneSpace(C, reports, name, overwrite);
119         }
120         else {
121                 ts = createObjectSpace(C, reports, name, overwrite);
122         }
123         
124         if (use && ts != NULL) {
125                 BIF_selectTransformOrientation(C, ts);
126         }
127 }
128
129 TransformOrientation *createObjectSpace(bContext *C, ReportList *UNUSED(reports), char *name, int overwrite)
130 {
131         Base *base = CTX_data_active_base(C);
132         Object *ob;
133         float mat[3][3];
134
135         if (base == NULL)
136                 return NULL;
137
138
139         ob = base->object;
140         
141         copy_m3_m4(mat, ob->obmat);
142         normalize_m3(mat);
143
144         /* use object name if no name is given */
145         if (name[0] == 0) {
146                 strncpy(name, ob->id.name + 2, MAX_ID_NAME - 2);
147         }
148
149         return addMatrixSpace(C, mat, name, overwrite); 
150 }
151
152 TransformOrientation *createBoneSpace(bContext *C, ReportList *reports, char *name, int overwrite)
153 {
154         float mat[3][3];
155         float normal[3], plane[3];
156
157         getTransformOrientation(C, normal, plane, 0);
158
159         if (createSpaceNormalTangent(mat, normal, plane) == 0) {
160                 BKE_reports_prepend(reports, "Cannot use zero-length bone");
161                 return NULL;
162         }
163
164         if (name[0] == 0) {
165                 strcpy(name, "Bone");
166         }
167
168         return addMatrixSpace(C, mat, name, overwrite);
169 }
170
171 TransformOrientation *createMeshSpace(bContext *C, ReportList *reports, char *name, int overwrite)
172 {
173         float mat[3][3];
174         float normal[3], plane[3];
175         int type;
176
177         type = getTransformOrientation(C, normal, plane, 0);
178         
179         switch (type) {
180                 case ORIENTATION_VERT:
181                         if (createSpaceNormal(mat, normal) == 0) {
182                                 BKE_reports_prepend(reports, "Cannot use vertex with zero-length normal");
183                                 return NULL;
184                         }
185         
186                         if (name[0] == 0) {
187                                 strcpy(name, "Vertex");
188                         }
189                         break;
190                 case ORIENTATION_EDGE:
191                         if (createSpaceNormalTangent(mat, normal, plane) == 0) {
192                                 BKE_reports_prepend(reports, "Cannot use zero-length edge");
193                                 return NULL;
194                         }
195         
196                         if (name[0] == 0) {
197                                 strcpy(name, "Edge");
198                         }
199                         break;
200                 case ORIENTATION_FACE:
201                         if (createSpaceNormalTangent(mat, normal, plane) == 0) {
202                                 BKE_reports_prepend(reports, "Cannot use zero-area face");
203                                 return NULL;
204                         }
205         
206                         if (name[0] == 0) {
207                                 strcpy(name, "Face");
208                         }
209                         break;
210                 default:
211                         return NULL;
212                         break;
213         }
214
215         return addMatrixSpace(C, mat, name, overwrite);
216 }
217
218 int createSpaceNormal(float mat[3][3], float normal[3])
219 {
220         float tangent[3] = {0.0f, 0.0f, 1.0f};
221         
222         copy_v3_v3(mat[2], normal);
223         if (normalize_v3(mat[2]) == 0.0f) {
224                 return 0; /* error return */
225         }
226
227         cross_v3_v3v3(mat[0], mat[2], tangent);
228         if (dot_v3v3(mat[0], mat[0]) == 0.0f) {
229                 tangent[0] = 1.0f;
230                 tangent[1] = tangent[2] = 0.0f;
231                 cross_v3_v3v3(mat[0], tangent, mat[2]);
232         }
233
234         cross_v3_v3v3(mat[1], mat[2], mat[0]);
235
236         normalize_m3(mat);
237         
238         return 1;
239 }
240
241 int createSpaceNormalTangent(float mat[3][3], float normal[3], float tangent[3])
242 {
243         copy_v3_v3(mat[2], normal);
244         if (normalize_v3(mat[2]) == 0.0f) {
245                 return 0; /* error return */
246         }
247         
248         /* preempt zero length tangent from causing trouble */
249         if (tangent[0] == 0 && tangent[1] == 0 && tangent[2] == 0) {
250                 tangent[2] = 1;
251         }
252
253         cross_v3_v3v3(mat[0], mat[2], tangent);
254         if (normalize_v3(mat[0]) == 0.0f) {
255                 return 0; /* error return */
256         }
257         
258         cross_v3_v3v3(mat[1], mat[2], mat[0]);
259
260         normalize_m3(mat);
261         
262         return 1;
263 }
264
265 TransformOrientation *addMatrixSpace(bContext *C, float mat[3][3], char name[], int overwrite)
266 {
267         ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
268         TransformOrientation *ts = NULL;
269
270         if (overwrite) {
271                 ts = findOrientationName(transform_spaces, name);
272         }
273         else {
274                 uniqueOrientationName(transform_spaces, name);
275         }
276
277         /* if not, create a new one */
278         if (ts == NULL) {
279                 ts = MEM_callocN(sizeof(TransformOrientation), "UserTransSpace from matrix");
280                 BLI_addtail(transform_spaces, ts);
281                 strncpy(ts->name, name, sizeof(ts->name));
282         }
283
284         /* copy matrix into transform space */
285         copy_m3_m3(ts->mat, mat);
286
287         return ts;
288 }
289
290 void BIF_removeTransformOrientation(bContext *C, TransformOrientation *target)
291 {
292         ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
293         TransformOrientation *ts;
294         int i;
295         
296         for (i = 0, ts = transform_spaces->first; ts; ts = ts->next, i++) {
297                 if (ts == target) {
298                         View3D *v3d = CTX_wm_view3d(C);
299                         if (v3d) {
300                                 int selected_index = (v3d->twmode - V3D_MANIP_CUSTOM);
301                                 
302                                 // Transform_fix_me NEED TO DO THIS FOR ALL VIEW3D
303                                 if (selected_index == i) {
304                                         v3d->twmode = V3D_MANIP_GLOBAL; /* fallback to global   */
305                                 }
306                                 else if (selected_index > i) {
307                                         v3d->twmode--;
308                                 }
309                                 
310                         }
311
312                         BLI_freelinkN(transform_spaces, ts);
313                         break;
314                 }
315         }
316 }
317
318 void BIF_removeTransformOrientationIndex(bContext *C, int index)
319 {
320         ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
321         TransformOrientation *ts = BLI_findlink(transform_spaces, index);
322
323         if (ts) {
324                 View3D *v3d = CTX_wm_view3d(C);
325                 if (v3d) {
326                         int selected_index = (v3d->twmode - V3D_MANIP_CUSTOM);
327                         
328                         // Transform_fix_me NEED TO DO THIS FOR ALL VIEW3D
329                         if (selected_index == index) {
330                                 v3d->twmode = V3D_MANIP_GLOBAL; /* fallback to global   */
331                         }
332                         else if (selected_index > index) {
333                                 v3d->twmode--;
334                         }
335                         
336                 }
337
338                 BLI_freelinkN(transform_spaces, ts);
339         }
340 }
341
342 void BIF_selectTransformOrientation(bContext *C, TransformOrientation *target)
343 {
344         ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
345         View3D *v3d = CTX_wm_view3d(C);
346         TransformOrientation *ts;
347         int i;
348         
349         for (i = 0, ts = transform_spaces->first; ts; ts = ts->next, i++) {
350                 if (ts == target) {
351                         v3d->twmode = V3D_MANIP_CUSTOM + i;
352                         break;
353                 }
354         }
355 }
356
357 void BIF_selectTransformOrientationValue(bContext *C, int orientation)
358 {
359         View3D *v3d = CTX_wm_view3d(C);
360         if (v3d) /* currently using generic poll */
361                 v3d->twmode = orientation;
362 }
363
364 EnumPropertyItem *BIF_enumTransformOrientation(bContext *C)
365 {
366         Scene *scene;
367         ListBase *transform_spaces;
368         TransformOrientation *ts = NULL;
369
370         EnumPropertyItem global = {V3D_MANIP_GLOBAL, "GLOBAL", 0, "Global", ""};
371         EnumPropertyItem normal = {V3D_MANIP_NORMAL, "NORMAL", 0, "Normal", ""};
372         EnumPropertyItem local = {V3D_MANIP_LOCAL, "LOCAL", 0, "Local", ""};
373         EnumPropertyItem view = {V3D_MANIP_VIEW, "VIEW", 0, "View", ""};
374         EnumPropertyItem tmp = {0, "", 0, "", ""};
375         EnumPropertyItem *item = NULL;
376         int i = V3D_MANIP_CUSTOM, totitem = 0;
377
378         RNA_enum_item_add(&item, &totitem, &global);
379         RNA_enum_item_add(&item, &totitem, &normal);
380         RNA_enum_item_add(&item, &totitem, &local);
381         RNA_enum_item_add(&item, &totitem, &view);
382
383         if (C) {
384                 scene = CTX_data_scene(C);
385
386                 if (scene) {
387                         transform_spaces = &scene->transform_spaces;
388                         ts = transform_spaces->first;
389                 }
390         }
391                 
392         if (ts)
393                 RNA_enum_item_add_separator(&item, &totitem);
394
395         for (; ts; ts = ts->next) {
396                 tmp.identifier = "CUSTOM";
397                 tmp.name = ts->name;
398                 tmp.value = i++;
399                 RNA_enum_item_add(&item, &totitem, &tmp);
400         }
401
402         RNA_enum_item_end(&item, &totitem);
403
404         return item;
405 }
406
407 const char *BIF_menustringTransformOrientation(const bContext *C, const char *title)
408 {
409         const char *menu = IFACE_("%t|Global%x0|Local%x1|Gimbal%x4|Normal%x2|View%x3");
410         ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
411         TransformOrientation *ts;
412         int i = V3D_MANIP_CUSTOM;
413         char *str_menu, *p;
414         const int elem_size = MAX_NAME + 4;
415
416         title = IFACE_(title);
417
418         str_menu = MEM_callocN(strlen(menu) + strlen(title) + 1 + elem_size * BIF_countTransformOrientation(C), TIP_("UserTransSpace from matrix"));
419         p = str_menu;
420         
421         p += sprintf(str_menu, "%s", title);
422         p += sprintf(p, "%s", menu);
423         
424         for (ts = transform_spaces->first; ts; ts = ts->next) {
425                 p += sprintf(p, "|%s%%x%d", ts->name, i++);
426         }
427         
428         return str_menu;
429 }
430
431 int BIF_countTransformOrientation(const bContext *C)
432 {
433         ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
434         TransformOrientation *ts;
435         int count = 0;
436
437         for (ts = transform_spaces->first; ts; ts = ts->next) {
438                 count++;
439         }
440         
441         return count;
442 }
443
444 void applyTransformOrientation(const bContext *C, float mat[3][3], char *name)
445 {
446         TransformOrientation *ts;
447         View3D *v3d = CTX_wm_view3d(C);
448         int selected_index = (v3d->twmode - V3D_MANIP_CUSTOM);
449         int i;
450         
451         if (selected_index >= 0) {
452                 for (i = 0, ts = CTX_data_scene(C)->transform_spaces.first; ts; ts = ts->next, i++) {
453                         if (selected_index == i) {
454                                 
455                                 if (name)
456                                         strcpy(name, ts->name);
457                                 
458                                 copy_m3_m3(mat, ts->mat);
459                                 break;
460                         }
461                 }
462         }
463 }
464
465 static int count_bone_select(bArmature *arm, ListBase *lb, int do_it) 
466 {
467         Bone *bone;
468         int do_next;
469         int total = 0;
470         
471         for (bone = lb->first; bone; bone = bone->next) {
472                 bone->flag &= ~BONE_TRANSFORM;
473                 do_next = do_it;
474                 if (do_it) {
475                         if (bone->layer & arm->layer) {
476                                 if (bone->flag & BONE_SELECTED) {
477                                         bone->flag |= BONE_TRANSFORM;
478                                         total++;
479                                         do_next = FALSE;    // no transform on children if one parent bone is selected
480                                 }
481                         }
482                 }
483                 total += count_bone_select(arm, &bone->childbase, do_next);
484         }
485         
486         return total;
487 }
488
489 void initTransformOrientation(bContext *C, TransInfo *t)
490 {
491         View3D *v3d = CTX_wm_view3d(C);
492         Object *ob = CTX_data_active_object(C);
493         Object *obedit = CTX_data_active_object(C);
494
495         switch (t->current_orientation) {
496                 case V3D_MANIP_GLOBAL:
497                         unit_m3(t->spacemtx);
498                         strcpy(t->spacename, "global");
499                         break;
500
501                 case V3D_MANIP_GIMBAL:
502                         unit_m3(t->spacemtx);
503                         if (gimbal_axis(ob, t->spacemtx)) {
504                                 strcpy(t->spacename, "gimbal");
505                                 break;
506                         }
507                 /* no gimbal fallthrough to normal */
508                 case V3D_MANIP_NORMAL:
509                         if (obedit || (ob && ob->mode & OB_MODE_POSE)) {
510                                 strcpy(t->spacename, "normal");
511                                 ED_getTransformOrientationMatrix(C, t->spacemtx, (v3d->around == V3D_ACTIVE));
512                                 break;
513                         }
514                 /* no break we define 'normal' as 'local' in Object mode */
515                 case V3D_MANIP_LOCAL:
516                         strcpy(t->spacename, "local");
517                 
518                         if (ob) {
519                                 copy_m3_m4(t->spacemtx, ob->obmat);
520                                 normalize_m3(t->spacemtx);
521                         }
522                         else {
523                                 unit_m3(t->spacemtx);
524                         }
525                 
526                         break;
527                 
528                 case V3D_MANIP_VIEW:
529                         if (t->ar->regiontype == RGN_TYPE_WINDOW) {
530                                 RegionView3D *rv3d = t->ar->regiondata;
531                                 float mat[3][3];
532
533                                 strcpy(t->spacename, "view");
534                                 copy_m3_m4(mat, rv3d->viewinv);
535                                 normalize_m3(mat);
536                                 copy_m3_m3(t->spacemtx, mat);
537                         }
538                         else {
539                                 unit_m3(t->spacemtx);
540                         }
541                         break;
542                 default: /* V3D_MANIP_CUSTOM */
543                         applyTransformOrientation(C, t->spacemtx, t->spacename);
544                         break;
545         }
546 }
547
548 int getTransformOrientation(const bContext *C, float normal[3], float plane[3], int activeOnly)
549 {
550         Scene *scene = CTX_data_scene(C);
551         View3D *v3d = CTX_wm_view3d(C);
552         Object *obedit = CTX_data_edit_object(C);
553         Base *base;
554         Object *ob = OBACT;
555         int result = ORIENTATION_NONE;
556
557         normal[0] = normal[1] = normal[2] = 0;
558         plane[0] = plane[1] = plane[2] = 0;
559
560         if (obedit) {
561                 float imat[3][3], mat[3][3];
562                 
563                 /* we need the transpose of the inverse for a normal... */
564                 copy_m3_m4(imat, ob->obmat);
565                 
566                 invert_m3_m3(mat, imat);
567                 transpose_m3(mat);
568
569                 ob = obedit;
570
571                 if (ob->type == OB_MESH) {
572                         Mesh *me = ob->data;
573                         BMEditMesh *em = me->edit_btmesh;
574                         BMVert *eve;
575                         BMEditSelection ese;
576                         float vec[3] = {0, 0, 0};
577                         
578                         /* USE LAST SELECTED WITH ACTIVE */
579                         if (activeOnly && BM_select_history_active_get(em->bm, &ese)) {
580                                 BM_editselection_normal(&ese, normal);
581                                 BM_editselection_plane(&ese, plane);
582                                 
583                                 switch (ese.htype) {
584                                         case BM_VERT:
585                                                 result = ORIENTATION_VERT;
586                                                 break;
587                                         case BM_EDGE:
588                                                 result = ORIENTATION_EDGE;
589                                                 break;
590                                         case BM_FACE:
591                                                 result = ORIENTATION_FACE;
592                                                 break;
593                                 }
594                         }
595                         else {
596                                 if (em->bm->totfacesel >= 1) {
597                                         BMFace *efa;
598                                         BMIter iter;
599
600                                         BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
601                                                 if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
602                                                         add_v3_v3(normal, efa->no);
603                                                         sub_v3_v3v3(vec,
604                                                                     BM_FACE_FIRST_LOOP(efa)->v->co,
605                                                                     BM_FACE_FIRST_LOOP(efa)->next->v->co);
606                                                         add_v3_v3(plane, vec);
607                                                 }
608                                         }
609                                         
610                                         result = ORIENTATION_FACE;
611                                 }
612                                 else if (em->bm->totvertsel == 3) {
613                                         BMVert *v1 = NULL, *v2 = NULL, *v3 = NULL;
614                                         BMIter iter;
615                                         float cotangent[3];
616                                         
617                                         BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
618                                                 if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
619                                                         if (v1 == NULL) {
620                                                                 v1 = eve; 
621                                                         }
622                                                         else if (v2 == NULL) {
623                                                                 v2 = eve;
624                                                         }
625                                                         else {
626                                                                 v3 = eve;
627
628                                                                 sub_v3_v3v3(plane, v2->co, v1->co);
629                                                                 sub_v3_v3v3(cotangent, v3->co, v2->co);
630                                                                 cross_v3_v3v3(normal, cotangent, plane);
631                                                                 break;
632                                                         }
633                                                 }
634                                         }
635
636                                         /* if there's an edge available, use that for the tangent */
637                                         if (em->bm->totedgesel >= 1) {
638                                                 BMEdge *eed = NULL;
639                                                 BMIter iter;
640                                                 
641                                                 BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
642                                                         if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
643                                                                 sub_v3_v3v3(plane, eed->v2->co, eed->v1->co);
644                                                                 break;
645                                                         }
646                                                 }
647                                         }
648
649                                         result = ORIENTATION_FACE;
650                                 }
651                                 else if (em->bm->totedgesel == 1) {
652                                         BMEdge *eed = NULL;
653                                         BMIter iter;
654                                         
655                                         BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
656                                                 if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
657                                                         /* use average vert normals as plane and edge vector as normal */
658                                                         copy_v3_v3(plane, eed->v1->no);
659                                                         add_v3_v3(plane, eed->v2->no);
660                                                         sub_v3_v3v3(normal, eed->v2->co, eed->v1->co);
661                                                         break;
662                                                 }
663                                         }
664                                         result = ORIENTATION_EDGE;
665                                 }
666                                 else if (em->bm->totvertsel == 2) {
667                                         BMVert *v1 = NULL, *v2 = NULL;
668                                         BMIter iter;
669
670                                         BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
671                                                 if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
672                                                         if (v1 == NULL) {
673                                                                 v1 = eve; 
674                                                         }
675                                                         else {
676                                                                 v2 = eve;
677                                                                 
678                                                                 copy_v3_v3(plane, v1->no);
679                                                                 add_v3_v3(plane, v2->no);
680                                                                 sub_v3_v3v3(normal, v2->co, v1->co);
681                                                                 break; 
682                                                         }
683                                                 }
684                                         }
685                                         result = ORIENTATION_EDGE;
686                                 }
687                                 else if (em->bm->totvertsel == 1) {
688                                         BMIter iter;
689
690                                         BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
691                                                 if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
692                                                         copy_v3_v3(normal, eve->no);
693                                                         break;
694                                                 }
695                                         }
696                                         result = ORIENTATION_VERT;
697                                 }
698                                 else if (em->bm->totvertsel > 3) {
699                                         BMIter iter;
700
701                                         zero_v3(normal);
702
703                                         BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
704                                                 if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
705                                                         add_v3_v3(normal, eve->no);
706                                                 }
707                                         }
708                                         normalize_v3(normal);
709                                         result = ORIENTATION_VERT;
710                                 }
711                         }
712                 } /* end editmesh */
713                 else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
714                         Curve *cu = obedit->data;
715                         Nurb *nu;
716                         BezTriple *bezt;
717                         int a;
718                         ListBase *nurbs = BKE_curve_editNurbs_get(cu);
719
720                         for (nu = nurbs->first; nu; nu = nu->next) {
721                                 /* only bezier has a normal */
722                                 if (nu->type == CU_BEZIER) {
723                                         bezt = nu->bezt;
724                                         a = nu->pntsu;
725                                         while (a--) {
726                                                 /* exception */
727                                                 if ((bezt->f1 & SELECT) + (bezt->f2 & SELECT) + (bezt->f3 & SELECT) > SELECT) {
728                                                         sub_v3_v3v3(normal, bezt->vec[0], bezt->vec[2]);
729                                                 }
730                                                 else {
731                                                         if (bezt->f1) {
732                                                                 sub_v3_v3v3(normal, bezt->vec[0], bezt->vec[1]);
733                                                         }
734                                                         if (bezt->f2) {
735                                                                 sub_v3_v3v3(normal, bezt->vec[0], bezt->vec[2]);
736                                                         }
737                                                         if (bezt->f3) {
738                                                                 sub_v3_v3v3(normal, bezt->vec[1], bezt->vec[2]);
739                                                         }
740                                                 }
741                                                 bezt++;
742                                         }
743                                 }
744                         }
745                         
746                         if (normal[0] != 0 || normal[1] != 0 || normal[2] != 0) {
747                                 result = ORIENTATION_NORMAL;
748                         }
749                 }
750                 else if (obedit->type == OB_MBALL) {
751 #if 0 // XXX
752                         /* editmball.c */
753                         MetaElem *ml, *ml_sel = NULL;
754         
755                         /* loop and check that only one element is selected */  
756                         for (ml = editelems.first; ml; ml = ml->next) {
757                                 if (ml->flag & SELECT) {
758                                         if (ml_sel == NULL) {
759                                                 ml_sel = ml;
760                                         }
761                                         else {
762                                                 ml_sel = NULL;
763                                                 break;
764                                         }
765                                 }
766                         }
767                         
768                         if (ml_sel) {   
769                                 float mat[4][4];
770
771                                 /* Rotation of MetaElem is stored in quat */
772                                 quat_to_mat4(mat, ml_sel->quat);
773
774                                 copy_v3_v3(normal, mat[2]);
775
776                                 negate_v3_v3(plane, mat[1]);
777                                 
778                                 result = ORIENTATION_NORMAL;
779                         }
780 #endif
781                         
782                 }
783                 else if (obedit->type == OB_ARMATURE) {
784                         bArmature *arm = obedit->data;
785                         EditBone *ebone;
786                         
787                         for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
788                                 if (arm->layer & ebone->layer) {
789                                         if (ebone->flag & BONE_SELECTED) {
790                                                 float tmat[3][3];
791                                                 float vec[3];
792                                                 sub_v3_v3v3(vec, ebone->tail, ebone->head);
793                                                 normalize_v3(vec);
794                                                 add_v3_v3(normal, vec);
795                                                 
796                                                 vec_roll_to_mat3(vec, ebone->roll, tmat);
797                                                 add_v3_v3(plane, tmat[2]);
798                                         }
799                                 }
800                         }
801                         
802                         normalize_v3(normal);
803                         normalize_v3(plane);
804
805                         if (plane[0] != 0 || plane[1] != 0 || plane[2] != 0) {
806                                 result = ORIENTATION_EDGE;
807                         }
808
809                 }
810
811                 /* Vectors from edges don't need the special transpose inverse multiplication */
812                 if (result == ORIENTATION_EDGE) {
813                         mul_mat3_m4_v3(ob->obmat, normal);
814                         mul_mat3_m4_v3(ob->obmat, plane);
815                 }
816                 else {
817                         mul_m3_v3(mat, normal);
818                         mul_m3_v3(mat, plane);
819                 }
820         }
821         else if (ob && (ob->mode & OB_MODE_POSE)) {
822                 bArmature *arm = ob->data;
823                 bPoseChannel *pchan;
824                 int totsel;
825                 
826                 totsel = count_bone_select(arm, &arm->bonebase, 1);
827                 if (totsel) {
828                         float imat[3][3], mat[3][3];
829
830                         /* use channels to get stats */
831                         for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
832                                 if (pchan->bone && pchan->bone->flag & BONE_TRANSFORM) {
833                                         add_v3_v3(normal, pchan->pose_mat[2]);
834                                         add_v3_v3(plane, pchan->pose_mat[1]);
835                                 }
836                         }
837                         negate_v3(plane);
838                         
839                         /* we need the transpose of the inverse for a normal... */
840                         copy_m3_m4(imat, ob->obmat);
841                         
842                         invert_m3_m3(mat, imat);
843                         transpose_m3(mat);
844                         mul_m3_v3(mat, normal);
845                         mul_m3_v3(mat, plane);
846                         
847                         result = ORIENTATION_EDGE;
848                 }
849         }
850         else if (ob && (ob->mode & (OB_MODE_ALL_PAINT | OB_MODE_PARTICLE_EDIT))) {
851                 /* pass */
852         }
853         else {
854                 /* we need the one selected object, if its not active */
855                 ob = OBACT;
856                 if (ob && !(ob->flag & SELECT)) ob = NULL;
857                 
858                 for (base = scene->base.first; base; base = base->next) {
859                         if (TESTBASELIB(v3d, base)) {
860                                 if (ob == NULL) {
861                                         ob = base->object;
862                                         break;
863                                 }
864                         }
865                 }
866                 
867                 if (ob) {
868                         copy_v3_v3(normal, ob->obmat[2]);
869                         copy_v3_v3(plane, ob->obmat[1]);
870                 }
871                 result = ORIENTATION_NORMAL;
872         }
873         
874         return result;
875 }
876
877 void ED_getTransformOrientationMatrix(const bContext *C, float orientation_mat[][3], int activeOnly)
878 {
879         float normal[3] = {0.0, 0.0, 0.0};
880         float plane[3] = {0.0, 0.0, 0.0};
881
882         int type;
883
884         type = getTransformOrientation(C, normal, plane, activeOnly);
885
886         switch (type) {
887                 case ORIENTATION_NORMAL:
888                         if (createSpaceNormalTangent(orientation_mat, normal, plane) == 0) {
889                                 type = ORIENTATION_NONE;
890                         }
891                         break;
892                 case ORIENTATION_VERT:
893                         if (createSpaceNormal(orientation_mat, normal) == 0) {
894                                 type = ORIENTATION_NONE;
895                         }
896                         break;
897                 case ORIENTATION_EDGE:
898                         if (createSpaceNormalTangent(orientation_mat, normal, plane) == 0) {
899                                 type = ORIENTATION_NONE;
900                         }
901                         break;
902                 case ORIENTATION_FACE:
903                         if (createSpaceNormalTangent(orientation_mat, normal, plane) == 0) {
904                                 type = ORIENTATION_NONE;
905                         }
906                         break;
907         }
908
909         if (type == ORIENTATION_NONE) {
910                 unit_m3(orientation_mat);
911         }
912 }