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