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