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