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