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