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