== Transform Orientations ==
authorMartin Poirier <theeth@yahoo.com>
Sun, 17 Feb 2008 22:19:02 +0000 (22:19 +0000)
committerMartin Poirier <theeth@yahoo.com>
Sun, 17 Feb 2008 22:19:02 +0000 (22:19 +0000)
Merge Normal orientation calculations with Custom Orientations, to make it work the same all accross the table:
- One or more faces: use average face normal (first edge of faces define tangent)
- One edge: use edge itself as normal (vertex normals define tangent)
- One vertex: use vertex normal (tangent is perpendicular to normal and z-axis)
- Two vertices => edge orientation
- Two vertices => face orientation

*I tested quite a bit but please report any bugs this might have caused.*

ADDED FILE WARNING: source/blender/src/transform_orientations.c

source/blender/include/transform.h
source/blender/src/transform.c
source/blender/src/transform_manipulator.c
source/blender/src/transform_orientations.c [new file with mode: 0644]

index 8f6d9bd75c75bc56eb47599fbe151927e7c99eb3..96e45da22da226feb6e06185d6207f9c7366e134 100644 (file)
@@ -481,6 +481,17 @@ int addMatrixSpace(float mat[3][3], char name[]);
 int addObjectSpace(struct Object *ob);
 void applyTransformOrientation(void);
 
+
+#define ORIENTATION_NONE       0
+#define ORIENTATION_NORMAL     1
+#define ORIENTATION_VERT       2
+#define ORIENTATION_EDGE       3
+#define ORIENTATION_FACE       4
+
+int getTransformOrientation(float normal[3], float plane[3], int activeOnly);
+int createSpaceNormal(float mat[3][3], float normal[3]);
+int createSpaceNormalTangent(float mat[3][3], float normal[3], float tangent[3]);
+
 #endif
 
 
index 8f8601da88ed6660cc6c03c0f7eb63da93bb9afa..87ca52dcfad67bc720eca3237d11f67290307f70 100644 (file)
@@ -57,8 +57,6 @@
 #include "DNA_object_types.h"
 #include "DNA_scene_types.h"           /* PET modes                    */
 #include "DNA_screen_types.h"  /* area dimensions              */
-#include "DNA_scene_types.h"
-#include "DNA_screen_types.h"
 #include "DNA_texture_types.h"
 #include "DNA_userdef_types.h"
 #include "DNA_view3d_types.h"
@@ -158,584 +156,7 @@ static void helpline(TransInfo *t, float *vec)
        }
 }
 
-/* *********************** TransSpace ************************** */
-void BIF_clearTransformOrientation(void)
-{
-       ListBase *transform_spaces = &G.scene->transform_spaces;
-       BLI_freelistN(transform_spaces);
-       
-       if (G.vd->twmode >= V3D_MANIP_CUSTOM)
-               G.vd->twmode = V3D_MANIP_GLOBAL;        /* fallback to global   */
-}
-  
-void BIF_manageTransformOrientation(int confirm, int set) {
-       int index = -1; 
-       
-       if (G.obedit) {
-               if (G.obedit->type == OB_MESH)
-                       index = manageMeshSpace(confirm, set);
-       }
-       else {
-               index = manageObjectSpace(confirm, set);
-       }
-       
-       if (set && index != -1)
-       {
-               BIF_selectTransformOrientationFromIndex(index);
-       }
-}
-
-int manageObjectSpace(int confirm, int set) {
-       Base *base = BASACT;
-
-       if (base == NULL)
-               return -1;
-
-       if (confirm == 0) {
-               if (set && pupmenu("Custom Orientation %t|Add and Use Active Object%x1") != 1) {
-                       return -1;
-               }
-               else if (set == 0 && pupmenu("Custom Orientation %t|Add Active Object%x1") != 1) {
-                       return -1;
-               }
-       }
-
-       return addObjectSpace(base->object);
-}
 
-/* return 1 on confirm */
-int confirmSpace(int set, char text[])
-{
-       char menu[64];
-       
-       if (set) {
-               sprintf(menu, "Custom Orientation %%t|Add and Use %s%%x1", text);
-       }
-       else {
-               sprintf(menu, "Custom Orientation %%t|Add %s%%x1", text);
-       }
-       
-       if (pupmenu(menu) == 1) {
-               return 1;
-       }
-       else {
-               return 0;
-       }
-}
-
-
-int manageMeshSpace(int confirm, int set) {
-       EditMesh *em = G.editMesh;
-       float mat[3][3];
-       char name[36] = "";
-       int index;
-
-       /* Vertice Selected */
-       if (G.scene->selectmode & SCE_SELECT_VERTEX && (G.totvertsel == 1 || G.totvertsel == 2 || G.totvertsel == 3)) {
-               if (G.totvertsel == 1) {
-                       /* EditSelection *ese; */
-                       EditVert *eve = NULL;
-                       float normal[3];
-       
-                       /*
-                       for (ese = em->selected.first; ese; ese = ese->next)
-                       {
-                               if ( ese->type == EDITVERT ) {
-                                       eve = (EditVert *)ese->data;
-                                       break;
-                               }
-                       }
-                       */
-                       
-                       for (eve = em->verts.first; eve; eve = eve->next)
-                       {
-                               if (eve->f & SELECT)
-                               {
-                                       break;
-                               }
-                       }
-                       
-                       if (eve == NULL)
-                               return -1;
-       
-                       if (confirm == 0 && confirmSpace(set, "vertex") == 0) {
-                               return -1;
-                       }
-       
-                       VECCOPY(normal, eve->no);
-                       Mat4Mul3Vecfl(G.obedit->obmat, normal);
-                       
-                       if (createSpaceNormal(mat, normal) == 0) {
-                               error("Cannot use vertex with zero-length normal");
-                               return -1;
-                       }
-       
-                       strcpy(name, "Vertex");
-               }
-               else if (G.totvertsel == 2) {
-                       /* EditSelection *ese; */
-                       EditVert *eve;
-                       EditVert *v1 = NULL, *v2 = NULL;
-                       float normal[3];
-
-                       /*      
-                       for (ese = em->selected.first; ese; ese = ese->next)
-                       {
-                               if ( ese->type == EDITVERT ) {
-                                       if (v1 == NULL) {
-                                               v1 = (EditVert *)ese->data; 
-                                       }
-                                       else {
-                                               v2 = (EditVert *)ese->data;
-                                               break; 
-                                       }
-                               }
-                       }
-                       */
-                       
-                       for (eve = em->verts.first; eve; eve = eve->next)
-                       {
-                               if ( eve->f & SELECT ) {
-                                       if (v1 == NULL) {
-                                               v1 = eve; 
-                                       }
-                                       else {
-                                               v2 = eve;
-                                               break; 
-                                       }
-                               }
-                       }
-
-                       if (v2 == NULL)
-                               return -1;
-       
-                       if (confirm == 0 && confirmSpace(set, "Edge") == 0) {
-                               return -1;
-                       }
-       
-                       VecSubf(normal, v2->co, v1->co);
-                       Mat4Mul3Vecfl(G.obedit->obmat, normal);
-                       
-                       if (createSpaceNormal(mat, normal) == 0) {
-                               error("Cannot use zero-length edge");
-                               return -1;
-                       }
-       
-                       strcpy(name, "Edge");
-               }
-               else if (G.totvertsel == 3) {
-                       /* EditSelection *ese; */
-                       EditVert *eve;
-                       EditVert *v1 = NULL, *v2 = NULL, *v3 = NULL;
-                       float normal[3], tangent[3], cotangent[3];
-       
-                       /*
-                       for (ese = em->selected.first; ese; ese = ese->next)
-                       {
-                               if ( ese->type == EDITVERT ) {
-                                       if (v1 == NULL) {
-                                               v1 = (EditVert *)ese->data; 
-                                       }
-                                       else if (v2 == NULL) {
-                                               v2 = (EditVert *)ese->data;
-                                       }
-                                       else {
-                                               v3 = (EditVert *)ese->data;
-                                               break; 
-                                       }
-                               }
-                       }
-                       */
-                       
-                       for (eve = em->verts.first; eve; eve = eve->next)
-                       {
-                               if ( eve->f & SELECT ) {
-                                       if (v1 == NULL) {
-                                               v1 = eve; 
-                                       }
-                                       else if (v2 == NULL) {
-                                               v2 = eve;
-                                       }
-                                       else {
-                                               v3 = eve;
-                                               break; 
-                                       }
-                               }
-                       }
-
-                       if (v3 == NULL)
-                               return -1;
-       
-                       if (confirm == 0 && confirmSpace(set, "Face") == 0) {
-                               return -1;
-                       }
-       
-                       VecSubf(tangent, v2->co, v1->co);
-                       VecSubf(cotangent, v3->co, v2->co);
-                       Crossf(normal, cotangent, tangent);
-                       
-                       Mat4Mul3Vecfl(G.obedit->obmat, normal);
-                       Mat4Mul3Vecfl(G.obedit->obmat, tangent);
-                       
-                       if (createSpaceNormal(mat, normal) == 0) {
-                               error("Cannot use zero-area face");
-                               return -1;
-                       }
-       
-                       strcpy(name, "Face");
-               }
-               
-       }
-       /* Edge Selected */
-       else if(G.scene->selectmode & SCE_SELECT_EDGE && (G.totedgesel == 1 || G.totedgesel == 2)) {
-               if (G.totedgesel == 1) {
-                       /* EditSelection *ese; */
-                       EditEdge *eed = NULL;
-                       float normal[3];
-       
-                       /*
-                       for (ese = em->selected.first; ese; ese = ese->next)
-                       {
-                               if ( ese->type == EDITEDGE ) {
-                                       eed = (EditEdge *)ese->data; 
-                                       break; 
-                               }
-                       }
-                       */
-                       
-                       for (eed = em->edges.first; eed; eed = eed->next)
-                       {
-                               if ( eed->f & SELECT ) {
-                                       break; 
-                               }
-                       }
-                       
-                       if (eed == NULL)
-                               return -1;
-       
-                       if (confirm == 0 && confirmSpace(set, "Edge") == 0) {
-                               return -1;
-                       }
-       
-                       VecSubf(normal, eed->v2->co, eed->v1->co);
-                       Mat4Mul3Vecfl(G.obedit->obmat, normal);
-                       
-                       if (createSpaceNormal(mat, normal) == 0) {
-                               error("Cannot use zero-length edge");
-                               return -1;
-                       }
-       
-                       strcpy(name, "Edge");
-               }
-               /* If selected edges form a triangle */
-               else if (G.totedgesel == 2 && G.totvertsel == 3) {
-                       /* EditSelection *ese; */
-                       EditEdge *eed;
-                       EditEdge *e1 = NULL, *e2 = NULL;
-                       EditVert *v1 = NULL, *v2 = NULL, *v3 = NULL;
-                       float normal[3], tangent[3], cotangent[3];
-
-                       /*
-                       for (ese = em->selected.first; ese; ese = ese->next)
-                       {
-                               if ( ese->type == EDITEDGE ) {
-                                       if (e1 == NULL) {
-                                               e1 = (EditEdge *)ese->data; 
-                                       }
-                                       else {
-                                               e2 = (EditEdge *)ese->data;
-                                               break; 
-                                       }
-                               }
-                       }
-                       */
-                       
-                       for (eed = em->edges.first; eed; eed = eed->next)
-                       {
-                               if ( eed->f & SELECT ) {
-                                       if (e1 == NULL) {
-                                               e1 = eed; 
-                                       }
-                                       else {
-                                               e2 = eed;
-                                               break; 
-                                       }
-                               }
-                       }
-
-                       if (e1->v1 == e2->v1) {
-                               v1 = e1->v2;
-                               v2 = e1->v1;
-                               v3 = e2->v2;
-                       }
-                       else if (e1->v1 == e2->v2) {
-                               v1 = e1->v2;
-                               v2 = e1->v1;
-                               v3 = e2->v1;
-                       }
-                       else if (e1->v2 == e2->v1) {
-                               v1 = e1->v1;
-                               v2 = e1->v2;
-                               v3 = e2->v2;
-                       }
-                       else if (e1->v2 == e2->v2) {
-                               v1 = e1->v1;
-                               v2 = e1->v2;
-                               v3 = e2->v1;
-                       }
-                       
-                       if (v1 == NULL)
-                               return -1;
-       
-                       if (confirm == 0 && confirmSpace(set, "Face") == 0) {
-                               return -1;
-                       }
-       
-                       VecSubf(tangent, v2->co, v1->co);
-                       VecSubf(cotangent, v3->co, v2->co);
-                       Crossf(normal, cotangent, tangent);
-                       
-                       Mat4Mul3Vecfl(G.obedit->obmat, normal);
-                       Mat4Mul3Vecfl(G.obedit->obmat, tangent);
-                       
-                       if (createSpaceNormal(mat, normal) == 0) {
-                               error("Cannot use zero-area face");
-                               return -1;
-                       }
-       
-                       strcpy(name, "Face");
-               }
-               
-       }
-       /* Face Selected */
-       else if(G.scene->selectmode & SCE_SELECT_FACE && G.totfacesel == 1) {
-               /* EditSelection *ese; */
-               EditFace *efa = NULL;
-               float normal[3], tangent[3];
-
-               /*
-               for (ese = em->selected.first; ese; ese = ese->next)
-               {
-                       if ( ese->type == EDITFACE ) {
-                               efa = (EditFace *)ese->data;
-                               break; 
-                       }
-               }
-               */
-               
-               for (efa = em->faces.first; efa; efa = efa->next)
-               {
-                       if (efa->f & SELECT)
-                       {
-                               break;
-                       }
-               }
-
-               if (efa == NULL)
-                       return -1;
-
-               if (confirm == 0 && confirmSpace(set, "Face") == 0) {
-                       return -1;
-               }
-
-               VECCOPY(normal, efa->n);
-               VecSubf(tangent, efa->v2->co, efa->v1->co);
-
-               Mat4Mul3Vecfl(G.obedit->obmat, normal);
-               Mat4Mul3Vecfl(G.obedit->obmat, tangent);
-               
-               if (createSpaceNormalTangent(mat, normal, tangent) == 0) {
-                       error("Cannot use zero-area face");
-                       return -1;
-               }
-
-               strcpy(name, "Face");
-       }
-       else {
-               return -1;
-       }
-
-       /* Input name */
-       sbutton(name, 1, 35, "name: ");
-
-       index = addMatrixSpace(mat, name);
-       return index;
-}
-
-int createSpaceNormal(float mat[3][3], float normal[3])
-{
-       float tangent[3] = {0.0f, 0.0f, 1.0f};
-       
-       VECCOPY(mat[2], normal);
-       if (Normalize(mat[2]) == 0.0f) {
-               return 0; /* error return */
-       }
-
-       Crossf(mat[0], mat[2], tangent);
-       if (Inpf(mat[0], mat[0]) == 0.0f) {
-               tangent[0] = 1.0f;
-               tangent[1] = tangent[2] = 0.0f;
-               Crossf(mat[0], tangent, mat[2]);
-       }
-
-       Crossf(mat[1], mat[2], mat[0]);
-
-       Mat3Ortho(mat);
-       
-       return 1;
-}
-
-int createSpaceNormalTangent(float mat[3][3], float normal[3], float tangent[3])
-{
-       VECCOPY(mat[2], normal);
-       if (Normalize(mat[2]) == 0.0f) {
-               return 0; /* error return */
-       }
-
-       Crossf(mat[0], mat[2], tangent);
-       if (Normalize(mat[0]) == 0.0f) {
-               return 0; /* error return */
-       }
-       
-       Crossf(mat[1], mat[2], mat[0]);
-
-       Mat3Ortho(mat);
-       
-       return 1;
-}
-
-
-int addObjectSpace(Object *ob) {
-       float mat[3][3];
-       char name[36] = "";
-
-       Mat3CpyMat4(mat, ob->obmat);
-       Mat3Ortho(mat);
-
-       strncpy(name, ob->id.name+2, 35);
-
-       /* Input name */
-       sbutton(name, 1, 35, "name: ");
-
-       return addMatrixSpace(mat, name);
-}
-
-int addMatrixSpace(float mat[3][3], char name[]) {
-       ListBase *transform_spaces = &G.scene->transform_spaces;
-       TransformOrientation *ts;
-       int index = 0;
-
-       /* if name is found in list, reuse that transform space */      
-       for (index = 0, ts = transform_spaces->first; ts; ts = ts->next, index++) {
-               if (strncmp(ts->name, name, 35) == 0) {
-                       break;
-               }
-       }
-
-       /* if not, create a new one */
-       if (ts == NULL)
-       {
-               ts = MEM_callocN(sizeof(TransformOrientation), "UserTransSpace from matrix");
-               BLI_addtail(transform_spaces, ts);
-               strncpy(ts->name, name, 35);
-       }
-
-       /* copy matrix into transform space */
-       Mat3CpyMat3(ts->mat, mat);
-
-       BIF_undo_push("Add/Update Transform Orientation");
-       
-       return index;
-}
-
-void BIF_removeTransformOrientation(TransformOrientation *target) {
-       ListBase *transform_spaces = &G.scene->transform_spaces;
-       TransformOrientation *ts = transform_spaces->first;
-       int selected_index = (G.vd->twmode - V3D_MANIP_CUSTOM);
-       int i;
-       
-       for (i = 0, ts = transform_spaces->first; ts; ts = ts->next, i++) {
-               if (ts == target) {
-                       if (selected_index == i) {
-                               G.vd->twmode = V3D_MANIP_GLOBAL;        /* fallback to global   */
-                       }
-                       else if (selected_index > i)
-                               G.vd->twmode--;
-
-                       BLI_freelinkN(transform_spaces, ts);
-                       break;
-               }
-       }
-       BIF_undo_push("Remove Transform Orientation");
-}
-
-void BIF_selectTransformOrientation(TransformOrientation *target) {
-       ListBase *transform_spaces = &G.scene->transform_spaces;
-       TransformOrientation *ts = transform_spaces->first;
-       int i;
-       
-       for (i = 0, ts = transform_spaces->first; ts; ts = ts->next, i++) {
-               if (ts == target) {
-                       G.vd->twmode = V3D_MANIP_CUSTOM + i;
-                       break;
-               }
-       }
-}
-
-void BIF_selectTransformOrientationFromIndex(int index) {
-       G.vd->twmode = V3D_MANIP_CUSTOM + index;
-}
-
-char * BIF_menustringTransformOrientation() {
-       char menu[] = "Orientation%t|Global%x0|Local%x1|Normal%x2|View%x3";
-       ListBase *transform_spaces = &G.scene->transform_spaces;
-       TransformOrientation *ts;
-       int i = V3D_MANIP_CUSTOM;
-       char *str_menu, *p;
-       
-       
-       str_menu = MEM_callocN(strlen(menu) + 40 * BIF_countTransformOrientation(), "UserTransSpace from matrix");
-       p = str_menu;
-       
-       p += sprintf(str_menu, "%s", menu);
-       
-       for (ts = transform_spaces->first; ts; ts = ts->next) {
-               p += sprintf(p, "|%s%%x%d", ts->name, i++);
-       }
-       
-       return str_menu;
-}
-
-int BIF_countTransformOrientation() {
-       ListBase *transform_spaces = &G.scene->transform_spaces;
-       TransformOrientation *ts;
-       int count = 0;
-
-       for (ts = transform_spaces->first; ts; ts = ts->next) {
-               count++;
-       }
-       
-       return count;
-}
-
-void applyTransformOrientation() {
-       TransInfo *t = BIF_GetTransInfo();
-       TransformOrientation *ts;
-       int selected_index = (G.vd->twmode - V3D_MANIP_CUSTOM);
-       int i;
-       
-       if (selected_index >= 0) {
-               for (i = 0, ts = G.scene->transform_spaces.first; ts; ts = ts->next, i++) {
-                       if (selected_index == i) {
-                               strcpy(t->spacename, ts->name);
-                               Mat3CpyMat3(t->spacemtx, ts->mat);
-                               Mat4CpyMat3(G.vd->twmat, ts->mat);
-                               break;
-                       }
-               }
-       }
-}
   
 /* ************************** INPUT FROM MOUSE *************************** */
 
index 13a8552b844609efeadd12cfc38c30d66b368412..734d917e9118421aff6998ffdb6a2984d00a2014 100644 (file)
@@ -234,53 +234,20 @@ int calc_manipulator_stats(ScrArea *sa)
                        EditMesh *em = G.editMesh;
                        EditVert *eve;
                        float vec[3]= {0,0,0};
-                       int no_faces= 1;
                        
                        /* USE LAST SELECTE WITH ACTIVE */
                        if (G.vd->around==V3D_ACTIVE && em->selected.last) {
                                EM_editselection_center(vec, em->selected.last);
                                calc_tw_center(vec);
                                totsel= 1;
-                               if (v3d->twmode == V3D_MANIP_NORMAL) {
-                                       EM_editselection_normal(normal, em->selected.last);
-                                       EM_editselection_plane(plane, em->selected.last);
-                               } /* NORMAL OPERATION */
                        } else {
-                               if(v3d->twmode == V3D_MANIP_NORMAL) {
-                                       EditFace *efa;
-                                       
-                                       for(efa= em->faces.first; efa; efa= efa->next) {
-                                               if(efa->f & SELECT) {
-                                                       no_faces= 0;
-                                                       VECADD(normal, normal, efa->n);
-                                                       VecSubf(vec, efa->v2->co, efa->v1->co);
-                                                       VECADD(plane, plane, vec);
-                                               }
-                                       }
-                               }
-                               
                                /* do vertices for center, and if still no normal found, use vertex normals */
                                for(eve= em->verts.first; eve; eve= eve->next) {
                                        if(eve->f & SELECT) {
-                                               if(no_faces) VECADD(normal, normal, eve->no);
-                                               
                                                totsel++;
                                                calc_tw_center(eve->co);
                                        }
                                }
-                               /* the edge case... */
-                               if(no_faces && v3d->twmode == V3D_MANIP_NORMAL) {
-                                       EditEdge *eed;
-                                       
-                                       for(eed= em->edges.first; eed; eed= eed->next) {
-                                               if(eed->f & SELECT) {
-                                                       /* ok we got an edge, only use one, and as normal */
-                                                       VECCOPY(plane, normal);
-                                                       VecSubf(normal, eed->v2->co, eed->v1->co);
-                                                       break;
-                                               }
-                                       }
-                               }
                        }
                } /* end editmesh */
                else if (G.obedit->type==OB_ARMATURE){
@@ -314,22 +281,18 @@ int calc_manipulator_stats(ScrArea *sa)
                                                if( (bezt->f1 & SELECT) + (bezt->f2 & SELECT) + (bezt->f3 & SELECT) > SELECT ) {
                                                        calc_tw_center(bezt->vec[1]);
                                                        totsel++;
-                                                       VecSubf(normal, bezt->vec[0], bezt->vec[2]);
                                                }
                                                else {
                                                        if(bezt->f1) {
                                                                calc_tw_center(bezt->vec[0]);
-                                                               VecSubf(normal, bezt->vec[0], bezt->vec[1]);
                                                                totsel++;
                                                        }
                                                        if(bezt->f2) {
                                                                calc_tw_center(bezt->vec[1]);
-                                                               VecSubf(normal, bezt->vec[0], bezt->vec[2]);
                                                                totsel++;
                                                        }
                                                        if(bezt->f3) {
                                                                calc_tw_center(bezt->vec[2]);
-                                                               VecSubf(normal, bezt->vec[1], bezt->vec[2]);
                                                                totsel++;
                                                        }
                                                }
@@ -364,23 +327,6 @@ int calc_manipulator_stats(ScrArea *sa)
                                }
                                ml= ml->next;
                        }
-                       /* normal manipulator */
-                       if(totsel==1){  
-                               float mat1[4][4];
-
-                               /* Rotation of MetaElem is stored in quat */
-                               QuatToMat4(ml_sel->quat, mat1);
-
-                               /* Translation of MetaElem */
-                               mat1[3][0]= ml_sel->x;
-                               mat1[3][1]= ml_sel->y;
-                               mat1[3][2]= ml_sel->z;
-
-                               VECCOPY(normal, mat1[2]);
-                               VECCOPY(plane, mat1[1]);
-
-                               VecMulf(plane, -1.0);
-                       }
                }
                else if(G.obedit->type==OB_LATTICE) {
                        BPoint *bp;
@@ -490,6 +436,54 @@ int calc_manipulator_stats(ScrArea *sa)
                        
                case V3D_MANIP_NORMAL:
                        if(G.obedit || (ob->flag & OB_POSEMODE)) {
+                               float mat[3][3];
+                               int type;
+
+                               strcpy(t->spacename, "normal");
+                       
+                               type = getTransformOrientation(normal, plane, 0);
+                               
+                               switch (type)
+                               {
+                                       case ORIENTATION_NORMAL:
+                                               if (createSpaceNormalTangent(mat, normal, plane) == 0)
+                                               {
+                                                       type = ORIENTATION_NONE;
+                                               }
+                                               break;
+                                       case ORIENTATION_VERT:
+                                               if (createSpaceNormal(mat, normal) == 0)
+                                               {
+                                                       type = ORIENTATION_NONE;
+                                               }
+                                               break;
+                                       case ORIENTATION_EDGE:
+                                               if (createSpaceNormalTangent(mat, normal, plane) == 0)
+                                               {
+                                                       type = ORIENTATION_NONE;
+                                               }
+                                               break;
+                                       case ORIENTATION_FACE:
+                                               if (createSpaceNormalTangent(mat, normal, plane) == 0)
+                                               {
+                                                       type = ORIENTATION_NONE;
+                                               }
+                                               break;
+                               }
+                               
+                               if (type == ORIENTATION_NONE)
+                               {
+                                       Mat4One(v3d->twmat);
+                               }
+                               else
+                               {
+                                       Mat4CpyMat3(v3d->twmat, mat);
+                               }
+                               break;
+                       }
+                       /* pose mode is a bit weird, so keep it separated */
+                       else if (ob->flag & OB_POSEMODE)
+                       {
                                strcpy(t->spacename, "normal");
                                if(normal[0]!=0.0 || normal[1]!=0.0 || normal[2]!=0.0) {
                                        float imat[3][3], mat[3][3];
diff --git a/source/blender/src/transform_orientations.c b/source/blender/src/transform_orientations.c
new file mode 100644 (file)
index 0000000..981d124
--- /dev/null
@@ -0,0 +1,616 @@
+/**
+ * $Id: 
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Contributor(s): Martin Poirier
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_curve_types.h"
+#include "DNA_listBase.h"
+#include "DNA_object_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_global.h"
+#include "BKE_utildefines.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+#include "BLI_editVert.h"
+
+#include "BIF_editmesh.h"
+#include "BIF_interface.h"
+#include "BIF_space.h"
+#include "BIF_toolbox.h"
+
+#include "blendef.h"
+
+
+#include "transform.h"
+
+
+/* *********************** TransSpace ************************** */
+
+void BIF_clearTransformOrientation(void)
+{
+       ListBase *transform_spaces = &G.scene->transform_spaces;
+       BLI_freelistN(transform_spaces);
+       
+       if (G.vd->twmode >= V3D_MANIP_CUSTOM)
+               G.vd->twmode = V3D_MANIP_GLOBAL;        /* fallback to global   */
+}
+void BIF_manageTransformOrientation(int confirm, int set) {
+       int index = -1; 
+       
+       if (G.obedit) {
+               if (G.obedit->type == OB_MESH)
+                       index = manageMeshSpace(confirm, set);
+       }
+       else {
+               index = manageObjectSpace(confirm, set);
+       }
+       
+       if (set && index != -1)
+       {
+               BIF_selectTransformOrientationFromIndex(index);
+       }
+}
+
+int manageObjectSpace(int confirm, int set) {
+       Base *base = BASACT;
+
+       if (base == NULL)
+               return -1;
+
+       if (confirm == 0) {
+               if (set && pupmenu("Custom Orientation %t|Add and Use Active Object%x1") != 1) {
+                       return -1;
+               }
+               else if (set == 0 && pupmenu("Custom Orientation %t|Add Active Object%x1") != 1) {
+                       return -1;
+               }
+       }
+
+       return addObjectSpace(base->object);
+}
+
+/* return 1 on confirm */
+int confirmSpace(int set, char text[])
+{
+       char menu[64];
+       
+       if (set) {
+               sprintf(menu, "Custom Orientation %%t|Add and Use %s%%x1", text);
+       }
+       else {
+               sprintf(menu, "Custom Orientation %%t|Add %s%%x1", text);
+       }
+       
+       if (pupmenu(menu) == 1) {
+               return 1;
+       }
+       else {
+               return 0;
+       }
+}
+
+
+int manageMeshSpace(int confirm, int set) {
+       float mat[3][3];
+       float normal[3], plane[3];
+       char name[36] = "";
+       int index;
+       int type;
+
+       type = getTransformOrientation(normal, plane, 0);
+       
+       switch (type)
+       {
+               case ORIENTATION_VERT:
+                       if (confirm == 0 && confirmSpace(set, "vertex") == 0) {
+                               return -1;
+                       }
+       
+                       if (createSpaceNormal(mat, normal) == 0) {
+                               error("Cannot use vertex with zero-length normal");
+                               return -1;
+                       }
+       
+                       strcpy(name, "Vertex");
+                       break;
+               case ORIENTATION_EDGE:
+                       if (confirm == 0 && confirmSpace(set, "Edge") == 0) {
+                               return -1;
+                       }
+       
+                       if (createSpaceNormalTangent(mat, normal, plane) == 0) {
+                               error("Cannot use zero-length edge");
+                               return -1;
+                       }
+       
+                       strcpy(name, "Edge");
+                       break;
+               case ORIENTATION_FACE:
+                       if (confirm == 0 && confirmSpace(set, "Face") == 0) {
+                               return -1;
+                       }
+       
+                       if (createSpaceNormalTangent(mat, normal, plane) == 0) {
+                               error("Cannot use zero-area face");
+                               return -1;
+                       }
+       
+                       strcpy(name, "Face");
+                       break;
+               default:
+                       return -1;
+                       break;
+       }
+
+       /* Input name */
+       sbutton(name, 1, 35, "name: ");
+
+       index = addMatrixSpace(mat, name);
+       return index;
+}
+
+int createSpaceNormal(float mat[3][3], float normal[3])
+{
+       float tangent[3] = {0.0f, 0.0f, 1.0f};
+       
+       VECCOPY(mat[2], normal);
+       if (Normalize(mat[2]) == 0.0f) {
+               return 0; /* error return */
+       }
+
+       Crossf(mat[0], mat[2], tangent);
+       if (Inpf(mat[0], mat[0]) == 0.0f) {
+               tangent[0] = 1.0f;
+               tangent[1] = tangent[2] = 0.0f;
+               Crossf(mat[0], tangent, mat[2]);
+       }
+
+       Crossf(mat[1], mat[2], mat[0]);
+
+       Mat3Ortho(mat);
+       
+       return 1;
+}
+
+int createSpaceNormalTangent(float mat[3][3], float normal[3], float tangent[3])
+{
+       VECCOPY(mat[2], normal);
+       if (Normalize(mat[2]) == 0.0f) {
+               return 0; /* error return */
+       }
+       
+       /* preempt zero length tangent from causing trouble */
+       if (tangent[0] == 0 && tangent[1] == 0 && tangent[2] == 0)
+       {
+               tangent[2] = 1;
+       }
+
+       Crossf(mat[0], mat[2], tangent);
+       if (Normalize(mat[0]) == 0.0f) {
+               return 0; /* error return */
+       }
+       
+       Crossf(mat[1], mat[2], mat[0]);
+
+       Mat3Ortho(mat);
+       
+       return 1;
+}
+
+
+int addObjectSpace(Object *ob) {
+       float mat[3][3];
+       char name[36] = "";
+
+       Mat3CpyMat4(mat, ob->obmat);
+       Mat3Ortho(mat);
+
+       strncpy(name, ob->id.name+2, 35);
+
+       /* Input name */
+       sbutton(name, 1, 35, "name: ");
+
+       return addMatrixSpace(mat, name);
+}
+
+int addMatrixSpace(float mat[3][3], char name[]) {
+       ListBase *transform_spaces = &G.scene->transform_spaces;
+       TransformOrientation *ts;
+       int index = 0;
+
+       /* if name is found in list, reuse that transform space */      
+       for (index = 0, ts = transform_spaces->first; ts; ts = ts->next, index++) {
+               if (strncmp(ts->name, name, 35) == 0) {
+                       break;
+               }
+       }
+
+       /* if not, create a new one */
+       if (ts == NULL)
+       {
+               ts = MEM_callocN(sizeof(TransformOrientation), "UserTransSpace from matrix");
+               BLI_addtail(transform_spaces, ts);
+               strncpy(ts->name, name, 35);
+       }
+
+       /* copy matrix into transform space */
+       Mat3CpyMat3(ts->mat, mat);
+
+       BIF_undo_push("Add/Update Transform Orientation");
+       
+       return index;
+}
+
+void BIF_removeTransformOrientation(TransformOrientation *target) {
+       ListBase *transform_spaces = &G.scene->transform_spaces;
+       TransformOrientation *ts = transform_spaces->first;
+       int selected_index = (G.vd->twmode - V3D_MANIP_CUSTOM);
+       int i;
+       
+       for (i = 0, ts = transform_spaces->first; ts; ts = ts->next, i++) {
+               if (ts == target) {
+                       if (selected_index == i) {
+                               G.vd->twmode = V3D_MANIP_GLOBAL;        /* fallback to global   */
+                       }
+                       else if (selected_index > i)
+                               G.vd->twmode--;
+
+                       BLI_freelinkN(transform_spaces, ts);
+                       break;
+               }
+       }
+       BIF_undo_push("Remove Transform Orientation");
+}
+
+void BIF_selectTransformOrientation(TransformOrientation *target) {
+       ListBase *transform_spaces = &G.scene->transform_spaces;
+       TransformOrientation *ts = transform_spaces->first;
+       int i;
+       
+       for (i = 0, ts = transform_spaces->first; ts; ts = ts->next, i++) {
+               if (ts == target) {
+                       G.vd->twmode = V3D_MANIP_CUSTOM + i;
+                       break;
+               }
+       }
+}
+
+void BIF_selectTransformOrientationFromIndex(int index) {
+       G.vd->twmode = V3D_MANIP_CUSTOM + index;
+}
+
+char * BIF_menustringTransformOrientation() {
+       char menu[] = "Orientation%t|Global%x0|Local%x1|Normal%x2|View%x3";
+       ListBase *transform_spaces = &G.scene->transform_spaces;
+       TransformOrientation *ts;
+       int i = V3D_MANIP_CUSTOM;
+       char *str_menu, *p;
+       
+       
+       str_menu = MEM_callocN(strlen(menu) + 40 * BIF_countTransformOrientation(), "UserTransSpace from matrix");
+       p = str_menu;
+       
+       p += sprintf(str_menu, "%s", menu);
+       
+       for (ts = transform_spaces->first; ts; ts = ts->next) {
+               p += sprintf(p, "|%s%%x%d", ts->name, i++);
+       }
+       
+       return str_menu;
+}
+
+int BIF_countTransformOrientation() {
+       ListBase *transform_spaces = &G.scene->transform_spaces;
+       TransformOrientation *ts;
+       int count = 0;
+
+       for (ts = transform_spaces->first; ts; ts = ts->next) {
+               count++;
+       }
+       
+       return count;
+}
+
+void applyTransformOrientation() {
+       TransInfo *t = BIF_GetTransInfo();
+       TransformOrientation *ts;
+       int selected_index = (G.vd->twmode - V3D_MANIP_CUSTOM);
+       int i;
+       
+       if (selected_index >= 0) {
+               for (i = 0, ts = G.scene->transform_spaces.first; ts; ts = ts->next, i++) {
+                       if (selected_index == i) {
+                               strcpy(t->spacename, ts->name);
+                               Mat3CpyMat3(t->spacemtx, ts->mat);
+                               Mat4CpyMat3(G.vd->twmat, ts->mat);
+                               break;
+                       }
+               }
+       }
+}
+
+
+int getTransformOrientation(float normal[3], float plane[3], int activeOnly)
+{
+       Base *base;
+       Object *ob = OBACT;
+       int result = ORIENTATION_NONE;
+
+       normal[0] = normal[1] = normal[2] = 0;
+       plane[0] = plane[1] = plane[2] = 0;
+
+       if(G.obedit)
+       {
+               ob= G.obedit;
+
+               if(G.obedit->type==OB_MESH)
+               {
+                       EditMesh *em = G.editMesh;
+                       EditVert *eve;
+                       float vec[3]= {0,0,0};
+                       
+                       /* USE LAST SELECTED WITH ACTIVE */
+                       if (activeOnly && em->selected.last)
+                       {
+                               EditSelection *ese = em->selected.last;
+                               EM_editselection_normal(normal, ese);
+                               EM_editselection_plane(plane, ese);
+                               
+                               switch (ese->type)
+                               {
+                                       case EDITVERT:
+                                               result = ORIENTATION_VERT;
+                                               break;
+                                       case EDITEDGE:
+                                               result = ORIENTATION_EDGE;
+                                               break;
+                                       case EDITFACE:
+                                               result = ORIENTATION_FACE;
+                                               break;
+                               }
+                       }
+                       else
+                       {
+                               if (G.totfacesel >= 1)
+                               {
+                                       EditFace *efa;
+                                       
+                                       for(efa= em->faces.first; efa; efa= efa->next)
+                                       {
+                                               if(efa->f & SELECT)
+                                               {
+                                                       VECADD(normal, normal, efa->n);
+                                                       VecSubf(vec, efa->v2->co, efa->v1->co);
+                                                       VECADD(plane, plane, vec);
+                                               }
+                                       }
+                                       
+                                       result = ORIENTATION_FACE;
+                               }
+                               else if (G.totvertsel == 3)
+                               {
+                                       EditVert *v1 = NULL, *v2 = NULL, *v3 = NULL;
+                                       float cotangent[3];
+                                       
+                                       for (eve = em->verts.first; eve; eve = eve->next)
+                                       {
+                                               if ( eve->f & SELECT ) {
+                                                       if (v1 == NULL) {
+                                                               v1 = eve; 
+                                                       }
+                                                       else if (v2 == NULL) {
+                                                               v2 = eve;
+                                                       }
+                                                       else {
+                                                               v3 = eve;
+
+                                                               VecSubf(plane, v2->co, v1->co);
+                                                               VecSubf(cotangent, v3->co, v2->co);
+                                                               Crossf(normal, cotangent, plane);
+                                                               break;
+                                                       }
+                                               }
+                                       }
+                                       result = ORIENTATION_FACE;
+                               }
+                               else if (G.totedgesel == 1)
+                               {
+                                       EditEdge *eed;
+
+                                       for(eed= em->edges.first; eed; eed= eed->next) {
+                                               if(eed->f & SELECT) {
+                                                       /* use average vert normals as plane and edge vector as normal */
+                                                       VECCOPY(plane, eed->v1->no);
+                                                       VECADD(plane, plane, eed->v2->no);
+                                                       VecSubf(normal, eed->v2->co, eed->v1->co);
+                                                       break;
+                                               }
+                                       }
+                                       result = ORIENTATION_EDGE;
+                               }
+                               else if (G.totvertsel == 2)
+                               {
+                                       EditVert *v1 = NULL, *v2 = NULL;
+               
+                                       for (eve = em->verts.first; eve; eve = eve->next)
+                                       {
+                                               if ( eve->f & SELECT ) {
+                                                       if (v1 == NULL) {
+                                                               v1 = eve; 
+                                                       }
+                                                       else {
+                                                               v2 = eve;
+                                                               
+                                                               VECCOPY(plane, v1->no);
+                                                               VECADD(plane, plane, v2->no);
+                                                               VecSubf(normal, v2->co, v1->co);
+                                                               break; 
+                                                       }
+                                               }
+                                       }
+                                       result = ORIENTATION_EDGE;
+                               }
+                               else if (G.totvertsel == 1)
+                               {
+                                       for (eve = em->verts.first; eve; eve = eve->next)
+                                       {
+                                               if ( eve->f & SELECT ) {
+                                                       VECCOPY(normal, eve->no);
+                                                       break;
+                                               }
+                                       }
+                                       result = ORIENTATION_VERT;
+                               }
+                       }
+               } /* end editmesh */
+               else if ELEM3(G.obedit->type, OB_CURVE, OB_SURF, OB_FONT)
+               {
+                       extern ListBase editNurb; /* BOOO! go away stupid extern */
+                       Nurb *nu;
+                       BezTriple *bezt;
+                       int a;
+                       
+                       for (nu = editNurb.first; nu; nu = nu->next)
+                       {
+                               /* only bezier has a normal */
+                               if((nu->type & 7) == CU_BEZIER)
+                               {
+                                       bezt= nu->bezt;
+                                       a= nu->pntsu;
+                                       while(a--)
+                                       {
+                                               /* exception */
+                                               if ( (bezt->f1 & SELECT) + (bezt->f2 & SELECT) + (bezt->f3 & SELECT) > SELECT )
+                                               {
+                                                       VecSubf(normal, bezt->vec[0], bezt->vec[2]);
+                                               }
+                                               else
+                                               {
+                                                       if(bezt->f1)
+                                                       {
+                                                               VecSubf(normal, bezt->vec[0], bezt->vec[1]);
+                                                       }
+                                                       if(bezt->f2)
+                                                       {
+                                                               VecSubf(normal, bezt->vec[0], bezt->vec[2]);
+                                                       }
+                                                       if(bezt->f3)
+                                                       {
+                                                               VecSubf(normal, bezt->vec[1], bezt->vec[2]);
+                                                       }
+                                               }
+                                               bezt++;
+                                       }
+                               }
+                       }
+                       
+                       if (normal[0] != 0 || normal[1] != 0 || normal[2] != 0)
+                       {
+                               result = ORIENTATION_NORMAL;
+                       }
+               }
+               else if(G.obedit->type==OB_MBALL)
+               {
+                       /* editmball.c */
+                       extern ListBase editelems;  /* go away ! */
+                       MetaElem *ml, *ml_sel = NULL;
+       
+                       /* loop and check that only one element is selected */  
+                       for (ml = editelems.first; ml; ml = ml->next)
+                       {
+                               if (ml->flag & SELECT) {
+                                       if (ml_sel == NULL)
+                                       {
+                                               ml_sel = ml;
+                                       }
+                                       else
+                                       {
+                                               ml_sel = NULL;
+                                               break;
+                                       }
+                               }
+                       }
+                       
+                       if (ml_sel)
+                       {       
+                               float mat[4][4];
+
+                               /* Rotation of MetaElem is stored in quat */
+                               QuatToMat4(ml_sel->quat, mat);
+
+                               VECCOPY(normal, mat[2]);
+                               VECCOPY(plane, mat[1]);
+
+                               VecMulf(plane, -1.0);
+                               
+                               result = ORIENTATION_NORMAL;
+                       }
+               }
+               
+               Mat4Mul3Vecfl(G.obedit->obmat, plane);
+               Mat4Mul3Vecfl(G.obedit->obmat, normal);
+       }
+       else if(ob && (ob->flag & OB_POSEMODE))
+       {
+       }
+       else if(G.f & (G_VERTEXPAINT + G_TEXTUREPAINT + G_WEIGHTPAINT + G_SCULPTMODE))
+       {
+       }
+       else if(G.f & G_PARTICLEEDIT)
+       {
+       }
+       else {
+               /* we need the one selected object, if its not active */
+               ob = OBACT;
+               if(ob && !(ob->flag & SELECT)) ob = NULL;
+               
+               for(base= G.scene->base.first; base; base= base->next) {
+                       if TESTBASELIB(base) {
+                               if(ob == NULL) { 
+                                       ob= base->object;
+                                       break;
+                               }
+                       }
+               }
+               
+               VECCOPY(normal, ob->obmat[2]);
+               VECCOPY(plane, ob->obmat[1]);
+               result = ORIENTATION_NORMAL;
+       }
+       
+       return result;
+}