diff options
author | Martin Poirier <theeth@yahoo.com> | 2008-12-29 04:41:28 +0300 |
---|---|---|
committer | Martin Poirier <theeth@yahoo.com> | 2008-12-29 04:41:28 +0300 |
commit | b6b61681efd322bd800bcaba55099cdf147547b2 (patch) | |
tree | bf745c0c58ee608ac8c3c53aa97a14932fc9135f /source/blender/editors/transform/transform_orientations.c | |
parent | 97a82102d4d24a94d8360a6f5f054e44f6fb1993 (diff) |
2.5
Transform:
First working port of the transform code:
- Object mode only (other conversions need to be ported)
- Contraints (global and local only) working
- Snap (no edit mode, obviously) working
- Numinput working
- Gears (Ctrl and Shift) working
- Only grap, rotate, scale, shear, warp and to sphere have been added as hotkey, but the rest should work too once accessible
- No manipulator
- No drawn feedback other than moving stuff and header print (no constraint line, snap circle, ...)
- No NDOF support
I've only tested Scons support, though Makefil *should* work, I *think*.
Misc:
-QuatIsNull function in arith
-Exporting project_* and view[line|ray] functions from view3d
Diffstat (limited to 'source/blender/editors/transform/transform_orientations.c')
-rw-r--r-- | source/blender/editors/transform/transform_orientations.c | 781 |
1 files changed, 781 insertions, 0 deletions
diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c new file mode 100644 index 00000000000..12a9c0e7214 --- /dev/null +++ b/source/blender/editors/transform/transform_orientations.c @@ -0,0 +1,781 @@ +/** + * $Id: + * + * ***** BEGIN GPL 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. + * + * 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 LICENSE BLOCK ***** + */ + +#include <string.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_armature_types.h" +#include "DNA_action_types.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_screen_types.h" +#include "DNA_space_types.h" +#include "DNA_view3d_types.h" + +#include "BKE_global.h" +#include "BKE_utildefines.h" +#include "BKE_armature.h" +#include "BKE_context.h" + +#include "BLI_arithb.h" +#include "BLI_blenlib.h" +#include "BLI_editVert.h" + +//#include "BIF_editmesh.h" +#include "BIF_editarmature.h" +//#include "BIF_interface.h" +//#include "BIF_space.h" +//#include "BIF_toolbox.h" + +#include "transform.h" + +#if 0 // TRANSFORM_FIX_ME + +/* *********************** TransSpace ************************** */ + +void BIF_clearTransformOrientation(void) +{ + ListBase *transform_spaces = &G.scene->transform_spaces; + BLI_freelistN(transform_spaces); + + // TRANSFORM_FIX_ME + // Need to loop over all view3d +// if (G.vd->twmode >= V3D_MANIP_CUSTOM) +// G.vd->twmode = V3D_MANIP_GLOBAL; /* fallback to global */ +} + +void BIF_manageTransformOrientation(int confirm, int set) { + Object *ob = OBACT; + int index = -1; + + if (G.obedit) { + if (G.obedit->type == OB_MESH) + index = manageMeshSpace(confirm, set); + else if (G.obedit->type == OB_ARMATURE) + index = manageBoneSpace(confirm, set); + } + else if (ob && (ob->flag & OB_POSEMODE)) { + index = manageBoneSpace(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 manageBoneSpace(int confirm, int set) { + float mat[3][3]; + float normal[3], plane[3]; + char name[36] = ""; + int index; + + getTransformOrientation(normal, plane, 0); + + if (confirm == 0 && confirmSpace(set, "Bone") == 0) { + return -1; + } + + if (createSpaceNormalTangent(mat, normal, plane) == 0) { + error("Cannot use zero-length bone"); + return -1; + } + + strcpy(name, "Bone"); + + /* Input name */ + sbutton(name, 1, 35, "name: "); + + index = addMatrixSpace(mat, name); + return index; +} + +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 *title) { + char menu[] = "%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) + strlen(title) + 1 + 40 * BIF_countTransformOrientation(), "UserTransSpace from matrix"); + p = str_menu; + + p += sprintf(str_menu, "%s", title); + p += sprintf(p, "%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; + } + } + } +} + +#endif // TRANSFORM_FIX_ME + +static int count_bone_select(bArmature *arm, ListBase *lb, int do_it) +{ + Bone *bone; + int do_next; + int total = 0; + + for(bone= lb->first; bone; bone= bone->next) { + bone->flag &= ~BONE_TRANSFORM; + do_next = do_it; + if(do_it) { + if(bone->layer & arm->layer) { + if (bone->flag & BONE_SELECTED) { + bone->flag |= BONE_TRANSFORM; + total++; + do_next= 0; // no transform on children if one parent bone is selected + } + } + } + total += count_bone_select(arm, &bone->childbase, do_next); + } + + return total; +} + +int getTransformOrientation(bContext *C, float normal[3], float plane[3], int activeOnly) +{ + Scene *scene = CTX_data_scene(C); + ScrArea *sa = CTX_wm_area(C); + View3D *v3d = sa->spacedata.first; + 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) + { + float imat[3][3], mat[3][3]; + + /* we need the transpose of the inverse for a normal... */ + Mat3CpyMat4(imat, ob->obmat); + + Mat3Inv(mat, imat); + Mat3Transp(mat); + + ob= G.obedit; + + if(G.obedit->type==OB_MESH) + { + EditMesh *em = G.editMesh; + EditVert *eve; + EditSelection ese; + float vec[3]= {0,0,0}; + + /* USE LAST SELECTED WITH ACTIVE */ + if (activeOnly && EM_get_actSelection(&ese)) + { + 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; + } + } + } + + /* if there's an edge available, use that for the tangent */ + if (G.totedgesel >= 1) + { + EditEdge *eed = NULL; + + for(eed= em->edges.first; eed; eed= eed->next) { + if(eed->f & SELECT) { + VecSubf(plane, eed->v2->co, eed->v1->co); + 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; + } + else if (G.totvertsel > 3) + { + normal[0] = normal[1] = normal[2] = 0; + + for (eve = em->verts.first; eve; eve = eve->next) + { + if ( eve->f & SELECT ) { + VecAddf(normal, normal, eve->no); + } + } + Normalize(normal); + 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; + } + } + else if (G.obedit->type == OB_ARMATURE) + { + bArmature *arm = G.obedit->data; + EditBone *ebone; + + for (ebone = G.edbo.first; ebone; ebone=ebone->next) { + if (arm->layer & ebone->layer) + { + if (ebone->flag & BONE_SELECTED) + { + float mat[3][3]; + float vec[3]; + VecSubf(vec, ebone->tail, ebone->head); + Normalize(vec); + VecAddf(normal, normal, vec); + + vec_roll_to_mat3(vec, ebone->roll, mat); + VecAddf(plane, plane, mat[2]); + } + } + } + + Normalize(normal); + Normalize(plane); + + if (plane[0] != 0 || plane[1] != 0 || plane[2] != 0) + { + result = ORIENTATION_EDGE; + } + + } + + /* Vectors from edges don't need the special transpose inverse multiplication */ + if (result == ORIENTATION_EDGE) + { + Mat4Mul3Vecfl(ob->obmat, normal); + Mat4Mul3Vecfl(ob->obmat, plane); + } + else + { + Mat3MulVecfl(mat, normal); + Mat3MulVecfl(mat, plane); + } + } + else if(ob && (ob->flag & OB_POSEMODE)) + { + bArmature *arm= ob->data; + bPoseChannel *pchan; + int totsel; + + totsel = count_bone_select(arm, &arm->bonebase, 1); + if(totsel) { + float imat[3][3], mat[3][3]; + + /* use channels to get stats */ + for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { + if (pchan->bone && pchan->bone->flag & BONE_TRANSFORM) { + VecAddf(normal, normal, pchan->pose_mat[2]); + VecAddf(plane, plane, pchan->pose_mat[1]); + } + } + VecMulf(plane, -1.0); + + /* we need the transpose of the inverse for a normal... */ + Mat3CpyMat4(imat, ob->obmat); + + Mat3Inv(mat, imat); + Mat3Transp(mat); + Mat3MulVecfl(mat, normal); + Mat3MulVecfl(mat, plane); + + result = ORIENTATION_EDGE; + } + } + 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(v3d, base) { + if(ob == NULL) { + ob= base->object; + break; + } + } + } + + VECCOPY(normal, ob->obmat[2]); + VECCOPY(plane, ob->obmat[1]); + result = ORIENTATION_NORMAL; + } + + return result; +} |