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/transform_orientations.c | |
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/transform_orientations.c')
-rw-r--r-- | source/blender/src/transform_orientations.c | 616 |
1 files changed, 616 insertions, 0 deletions
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; +} |