diff options
author | Martin Poirier <theeth@yahoo.com> | 2008-02-18 01:19:02 +0300 |
---|---|---|
committer | Martin Poirier <theeth@yahoo.com> | 2008-02-18 01:19:02 +0300 |
commit | 83ddab60b72b693faa77068d77eb35f5555b81d2 (patch) | |
tree | 1442000f4bf7ba64fb26b376a7299b3a72bb5713 /source/blender/src | |
parent | 417687c4ff052fccd6b8da3931fc85d231504773 (diff) |
== Transform Orientations ==
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
Diffstat (limited to 'source/blender/src')
-rw-r--r-- | source/blender/src/transform.c | 579 | ||||
-rw-r--r-- | source/blender/src/transform_manipulator.c | 102 | ||||
-rw-r--r-- | source/blender/src/transform_orientations.c | 616 |
3 files changed, 664 insertions, 633 deletions
diff --git a/source/blender/src/transform.c b/source/blender/src/transform.c index 8f8601da88e..87ca52dcfad 100644 --- a/source/blender/src/transform.c +++ b/source/blender/src/transform.c @@ -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 *************************** */ diff --git a/source/blender/src/transform_manipulator.c b/source/blender/src/transform_manipulator.c index 13a8552b844..734d917e911 100644 --- a/source/blender/src/transform_manipulator.c +++ b/source/blender/src/transform_manipulator.c @@ -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 index 00000000000..981d124c23b --- /dev/null +++ b/source/blender/src/transform_orientations.c @@ -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; +} |