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