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