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