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