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