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