diff options
Diffstat (limited to 'source/blender/src/transform_snap.c')
-rw-r--r-- | source/blender/src/transform_snap.c | 617 |
1 files changed, 504 insertions, 113 deletions
diff --git a/source/blender/src/transform_snap.c b/source/blender/src/transform_snap.c index 0e69e823d92..d16308f17ae 100644 --- a/source/blender/src/transform_snap.c +++ b/source/blender/src/transform_snap.c @@ -55,11 +55,13 @@ #include "BIF_screen.h" #include "BIF_editsima.h" #include "BIF_drawimage.h" +#include "BIF_editmesh.h" #include "BKE_global.h" #include "BKE_utildefines.h" #include "BKE_DerivedMesh.h" #include "BKE_object.h" +#include "BKE_anim.h" /* for duplis */ #include "BSE_view.h" @@ -92,7 +94,8 @@ float ResizeBetween(TransInfo *t, float p1[3], float p2[3]); /* Modes */ #define NOT_SELECTED 0 #define NOT_ACTIVE 1 -int findNearestVertFromObjects(int *dist, float *loc, int mode); +int snapObjects(int *dist, float *loc, float *no, int mode); + /****************** IMPLEMENTATIONS *********************/ @@ -131,6 +134,15 @@ void drawSnapping(TransInfo *t) glTranslatef(t->tsnap.snapPoint[0], t->tsnap.snapPoint[1], t->tsnap.snapPoint[2]); + /* draw normal if needed */ + if (usingSnappingNormal(t) && validSnappingNormal(t)) + { + glBegin(GL_LINES); + glVertex3f(0, 0, 0); + glVertex3f(t->tsnap.snapNormal[0], t->tsnap.snapNormal[1], t->tsnap.snapNormal[2]); + glEnd(); + } + /* sets view screen aligned */ glRotatef( -360.0f*saacos(G.vd->viewquat[0])/(float)M_PI, G.vd->viewquat[1], G.vd->viewquat[2], G.vd->viewquat[3]); @@ -201,7 +213,8 @@ void applySnapping(TransInfo *t, float *vec) double current = PIL_check_seconds_timer(); // Time base quirky code to go around findnearest slowness - if (current - t->tsnap.last >= 0.25) + /* !TODO! add exception for object mode, no need to slow it down then */ + if (current - t->tsnap.last >= 0.1) { t->tsnap.calcSnap(t, vec); t->tsnap.targetSnap(t); @@ -222,6 +235,35 @@ void resetSnapping(TransInfo *t) t->tsnap.modeTarget = 0; t->tsnap.last = 0; t->tsnap.applySnap = NULL; + + t->tsnap.snapNormal[0] = 0; + t->tsnap.snapNormal[1] = 0; + t->tsnap.snapNormal[2] = 0; +} + +int usingSnappingNormal(TransInfo *t) +{ + if (G.scene->snap_flag & SCE_SNAP_ROTATE) + { + return 1; + } + else + { + return 0; + } +} + +int validSnappingNormal(TransInfo *t) +{ + if ((t->tsnap.status & (POINT_INIT|TARGET_INIT)) == (POINT_INIT|TARGET_INIT)) + { + if (Inpf(t->tsnap.snapNormal, t->tsnap.snapNormal) > 0) + { + return 1; + } + } + + return 0; } void initSnapping(TransInfo *t) @@ -370,7 +412,7 @@ float RotationBetween(TransInfo *t, float p1[3], float p2[3]) if (t->con.applyRot != NULL && (t->con.mode & CON_APPLY)) { float axis[3], tmp[3]; - t->con.applyRot(t, NULL, axis); + t->con.applyRot(t, NULL, axis, NULL); Projf(tmp, end, axis); VecSubf(end, end, tmp); @@ -445,14 +487,26 @@ void CalcSnapGeometry(TransInfo *t, float *vec) if (t->spacetype == SPACE_VIEW3D) { float vec[3]; + float no[3]; int found = 0; int dist = 40; // Use a user defined value here - found = findNearestVertFromObjects(&dist, vec, NOT_SELECTED); + found = snapObjects(&dist, vec, no, NOT_SELECTED); if (found == 1) { - VECCOPY(t->tsnap.snapPoint, vec); + float tangent[3]; + + VecSubf(tangent, vec, t->tsnap.snapPoint); + tangent[2] = 0; + + if (Inpf(tangent, tangent) > 0) + { + VECCOPY(t->tsnap.snapTangent, tangent); + } + VECCOPY(t->tsnap.snapPoint, vec); + VECCOPY(t->tsnap.snapNormal, no); + t->tsnap.status |= POINT_INIT; } else @@ -464,31 +518,18 @@ void CalcSnapGeometry(TransInfo *t, float *vec) /* Mesh edit mode */ else if (G.obedit != NULL && G.obedit->type==OB_MESH) { - /*if (G.scene->selectmode & B_SEL_VERT)*/ - if (t->spacetype == SPACE_VIEW3D) { - EditVert *nearest=NULL; float vec[3]; + float no[3]; int found = 0; int dist = 40; // Use a user defined value here - - // use findnearestverts in vert mode, others in other modes - nearest = findnearestvert(&dist, SELECT, 1); - - found = findNearestVertFromObjects(&dist, vec, NOT_ACTIVE); + + found = snapObjects(&dist, vec, no, NOT_ACTIVE); if (found == 1) { VECCOPY(t->tsnap.snapPoint, vec); - - t->tsnap.status |= POINT_INIT; - } - /* If there's no outside vertex nearer, but there's one in this mesh - */ - else if (nearest != NULL) - { - VECCOPY(t->tsnap.snapPoint, nearest->co); - Mat4MulVecfl(G.obedit->obmat, t->tsnap.snapPoint); + VECCOPY(t->tsnap.snapNormal, no); t->tsnap.status |= POINT_INIT; } @@ -522,33 +563,6 @@ void CalcSnapGeometry(TransInfo *t, float *vec) t->tsnap.status &= ~POINT_INIT; } } - - - /* - if (G.scene->selectmode & B_SEL_EDGE) - { - EditEdge *nearest=NULL; - int dist = 50; // Use a user defined value here - - // use findnearestverts in vert mode, others in other modes - nearest = findnearestedge(&dist); - - if (nearest != NULL) - { - VecAddf(t->tsnap.snapPoint, nearest->v1->co, nearest->v2->co); - - VecMulf(t->tsnap.snapPoint, 0.5f); - - Mat4MulVecfl(G.obedit->obmat, t->tsnap.snapPoint); - - t->tsnap.status |= POINT_INIT; - } - else - { - t->tsnap.status &= ~POINT_INIT; - } - } - */ } } @@ -723,101 +737,478 @@ void TargetSnapClosest(TransInfo *t) } /*================================================================*/ -int findNearestVertFromObjects(int *dist, float *loc, int mode) { - Base *base; +int snapDerivedMesh(Object *ob, DerivedMesh *dm, float obmat[][4], float ray_start[3], float ray_normal[3], short mval[2], float *loc, float *no, int *dist, float *depth, short EditMesh) +{ int retval = 0; - short mval[2]; + int totvert = dm->getNumVerts(dm); + int totface = dm->getNumFaces(dm); - getmouseco_areawin(mval); - - base= FIRSTBASE; - for ( base = FIRSTBASE; base != NULL; base = base->next ) { - if ( BASE_SELECTABLE(base) && ((mode == NOT_SELECTED && (base->flag & SELECT) == 0) || (mode == NOT_ACTIVE && base != BASACT)) ) { - Object *ob = base->object; + if (totvert > 0) { + float imat[4][4]; + float timat[3][3]; /* transpose inverse matrix for normals */ + float ray_start_local[3], ray_normal_local[3]; + int test = 1; + + Mat4Invert(imat, obmat); + + Mat3CpyMat4(timat, imat); + Mat3Transp(timat); + + VECCOPY(ray_start_local, ray_start); + VECCOPY(ray_normal_local, ray_normal); + + Mat4MulVecfl(imat, ray_start_local); + Mat4Mul3Vecfl(imat, ray_normal_local); + + + /* If number of vert is more than an arbitrary limit, + * test against boundbox first + * */ + if (totface > 16) { + struct BoundBox *bb = object_get_boundbox(ob); + test = ray_hit_boundbox(bb, ray_start_local, ray_normal_local); + } + + if (test == 1) { - if (ob->type == OB_MESH) { - Mesh *me = ob->data; - - if (me->totvert > 0) { - int test = 1; + switch (G.scene->snap_mode) + { + case SCE_SNAP_MODE_FACE: + { + MVert *verts = dm->getVertArray(dm); + MFace *faces = dm->getFaceArray(dm); + int *index_array = NULL; + int index = 0; int i; - /* If number of vert is more than an arbitrary limit, - * test against boundbox first - * */ - if (me->totvert > 16) { - struct BoundBox *bb = object_get_boundbox(ob); + if (EditMesh) + { + index_array = dm->getFaceDataArray(dm, CD_ORIGINDEX); + EM_init_index_arrays(0, 0, 1); + } + + for( i = 0; i < totface; i++) { + EditFace *efa = NULL; + MFace *f = faces + i; + float lambda; + int result; + + test = 1; /* reset for every face */ + + if (EditMesh) + { + if (index_array) + { + index = index_array[i]; + } + else + { + index = i; + } + + if (index == ORIGINDEX_NONE) + { + test = 0; + } + else + { + efa = EM_get_face_for_index(index); + + if (efa && efa->f & SELECT) + { + test = 0; + } + } + } - int minx = 0, miny = 0, maxx = 0, maxy = 0; - int i; - for (i = 0; i < 8; i++) { - float gloc[3]; - int sloc[2]; + if (test) + { + result = RayIntersectsTriangle(ray_start_local, ray_normal_local, verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, &lambda, NULL); - VECCOPY(gloc, bb->vec[i]); - Mat4MulVecfl(ob->obmat, gloc); - project_int(gloc, sloc); + if (result) { + float location[3], normal[3]; + float intersect[3]; + float new_depth; + int screen_loc[2]; + int new_dist; + + VECCOPY(intersect, ray_normal_local); + VecMulf(intersect, lambda); + VecAddf(intersect, intersect, ray_start_local); + + VECCOPY(location, intersect); + + if (f->v4) + CalcNormFloat4(verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, verts[f->v4].co, normal); + else + CalcNormFloat(verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, normal); + + Mat4MulVecfl(obmat, location); + + new_depth = VecLenf(location, ray_start); + + project_int(location, screen_loc); + new_dist = abs(screen_loc[0] - mval[0]) + abs(screen_loc[1] - mval[1]); + + if (new_dist <= *dist && new_depth < *depth) + { + *depth = new_depth; + retval = 1; + + VECCOPY(loc, location); + VECCOPY(no, normal); + + Mat3MulVecfl(timat, no); + Normalize(no); + + *dist = new_dist; + } + } + + if (f->v4 && result == 0) + { + result = RayIntersectsTriangle(ray_start_local, ray_normal_local, verts[f->v3].co, verts[f->v4].co, verts[f->v1].co, &lambda, NULL); + + if (result) { + float location[3], normal[3]; + float intersect[3]; + float new_depth; + int screen_loc[2]; + int new_dist; + + VECCOPY(intersect, ray_normal_local); + VecMulf(intersect, lambda); + VecAddf(intersect, intersect, ray_start_local); + + VECCOPY(location, intersect); + + if (f->v4) + CalcNormFloat4(verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, verts[f->v4].co, normal); + else + CalcNormFloat(verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, normal); + + Mat4MulVecfl(obmat, location); + + new_depth = VecLenf(location, ray_start); + + project_int(location, screen_loc); + new_dist = abs(screen_loc[0] - mval[0]) + abs(screen_loc[1] - mval[1]); + + if (new_dist <= *dist && new_depth < *depth) + { + *depth = new_depth; + retval = 1; + + VECCOPY(loc, location); + VECCOPY(no, normal); + + Mat3MulVecfl(timat, no); + Normalize(no); + + *dist = new_dist; + } + } + } + } + } + + if (EditMesh) + { + EM_free_index_arrays(); + } + break; + } + case SCE_SNAP_MODE_VERTEX: + { + MVert *verts = dm->getVertArray(dm); + int *index_array = NULL; + int index = 0; + int i; + + if (EditMesh) + { + index_array = dm->getVertDataArray(dm, CD_ORIGINDEX); + EM_init_index_arrays(1, 0, 0); + } + + for( i = 0; i < totvert; i++) { + EditVert *eve = NULL; + MVert *v = verts + i; + + test = 1; /* reset for every vert */ + + if (EditMesh) + { + if (index_array) + { + index = index_array[i]; + } + else + { + index = i; + } - if (i == 0) { - minx = maxx = sloc[0]; - miny = maxy = sloc[1]; + if (index == ORIGINDEX_NONE) + { + test = 0; } - else { - if (minx > sloc[0]) minx = sloc[0]; - else if (maxx < sloc[0]) maxx = sloc[0]; + else + { + eve = EM_get_vert_for_index(index); - if (miny > sloc[1]) miny = sloc[1]; - else if (maxy < sloc[1]) maxy = sloc[1]; + if (eve && eve->f & SELECT) + { + test = 0; + } } } - /* Pad with distance */ - - minx -= *dist; - miny -= *dist; - maxx += *dist; - maxy += *dist; - if (mval[0] > maxx || mval[0] < minx || - mval[1] > maxy || mval[1] < miny) { + if (test) + { + float dvec[3]; + + VecSubf(dvec, v->co, ray_start_local); - test = 0; + if (Inpf(ray_normal_local, dvec) > 0) + { + float location[3]; + float new_depth; + int screen_loc[2]; + int new_dist; + + VECCOPY(location, v->co); + + Mat4MulVecfl(obmat, location); + + new_depth = VecLenf(location, ray_start); + + project_int(location, screen_loc); + new_dist = abs(screen_loc[0] - mval[0]) + abs(screen_loc[1] - mval[1]); + + if (new_dist <= *dist && new_depth < *depth) + { + *depth = new_depth; + retval = 1; + + VECCOPY(loc, location); + + NormalShortToFloat(no, v->no); + Mat3MulVecfl(timat, no); + Normalize(no); + + *dist = new_dist; + } + } } } + + if (EditMesh) + { + EM_free_index_arrays(); + } + break; + } + case SCE_SNAP_MODE_EDGE: + { + MVert *verts = dm->getVertArray(dm); + MEdge *edges = dm->getEdgeArray(dm); + int totedge = dm->getNumEdges(dm); + int *index_array = NULL; + int index = 0; + int i; - if (test == 1) { - float *verts = mesh_get_mapped_verts_nors(ob); + if (EditMesh) + { + index_array = dm->getEdgeDataArray(dm, CD_ORIGINDEX); + EM_init_index_arrays(0, 1, 0); + } + + for( i = 0; i < totedge; i++) { + EditEdge *eed = NULL; + MEdge *e = edges + i; - if (verts != NULL) { - float *fp; + test = 1; /* reset for every vert */ + + if (EditMesh) + { + if (index_array) + { + index = index_array[i]; + } + else + { + index = i; + } - fp = verts; - for( i = 0; i < me->totvert; i++, fp += 6) { - float gloc[3]; - int sloc[2]; - int curdist; + if (index == ORIGINDEX_NONE) + { + test = 0; + } + else + { + eed = EM_get_edge_for_index(index); - VECCOPY(gloc, fp); - Mat4MulVecfl(ob->obmat, gloc); - project_int(gloc, sloc); + if (eed && ((eed->v1->f & SELECT) || (eed->v2->f & SELECT))) + { + test = 0; + } + } + } + + + if (test) + { + float intersect[3] = {0, 0, 0}, ray_end[3], dvec[3]; + int result; + + VECCOPY(ray_end, ray_normal_local); + VecMulf(ray_end, 2000); + VecAddf(ray_end, ray_start_local, ray_end); + + result = LineIntersectLine(verts[e->v1].co, verts[e->v2].co, ray_start_local, ray_end, intersect, dvec); /* dvec used but we don't care about result */ + + if (result) + { + float edge_loc[3], vec[3]; + float mul; + + /* check for behind ray_start */ + VecSubf(dvec, intersect, ray_start_local); - sloc[0] -= mval[0]; - sloc[1] -= mval[1]; + VecSubf(edge_loc, verts[e->v1].co, verts[e->v2].co); + VecSubf(vec, intersect, verts[e->v2].co); - curdist = abs(sloc[0]) + abs(sloc[1]); + mul = Inpf(vec, edge_loc) / Inpf(edge_loc, edge_loc); - if (curdist < *dist) { - *dist = curdist; - retval = 1; - VECCOPY(loc, gloc); + if (mul > 1) { + mul = 1; + VECCOPY(intersect, verts[e->v1].co); + } + else if (mul < 0) { + mul = 0; + VECCOPY(intersect, verts[e->v2].co); + } + + if (Inpf(ray_normal_local, dvec) > 0) + { + float location[3]; + float new_depth; + int screen_loc[2]; + int new_dist; + + VECCOPY(location, intersect); + + Mat4MulVecfl(obmat, location); + + new_depth = VecLenf(location, ray_start); + + project_int(location, screen_loc); + new_dist = abs(screen_loc[0] - mval[0]) + abs(screen_loc[1] - mval[1]); + + if (new_dist <= *dist && new_depth < *depth) + { + float n1[3], n2[3]; + + *depth = new_depth; + retval = 1; + + VecSubf(edge_loc, verts[e->v1].co, verts[e->v2].co); + VecSubf(vec, intersect, verts[e->v2].co); + + mul = Inpf(vec, edge_loc) / Inpf(edge_loc, edge_loc); + + NormalShortToFloat(n1, verts[e->v1].no); + NormalShortToFloat(n2, verts[e->v2].no); + VecLerpf(no, n2, n1, mul); + Normalize(no); + + VECCOPY(loc, location); + + Mat3MulVecfl(timat, no); + Normalize(no); + + *dist = new_dist; + } } } } + } + + if (EditMesh) + { + EM_free_index_arrays(); + } + break; + } + } + } + } + + return retval; +} + +int snapObjects(int *dist, float *loc, float *no, int mode) { + Base *base; + float depth = FLT_MAX; + int retval = 0; + short mval[2]; + float ray_start[3], ray_normal[3]; + + getmouseco_areawin(mval); + viewray(mval, ray_start, ray_normal); - MEM_freeN(verts); + if (mode == NOT_ACTIVE) + { + DerivedMesh *dm; + Object *ob = G.obedit; + + dm = editmesh_get_derived_cage(CD_MASK_BAREMESH); + + retval = snapDerivedMesh(ob, dm, ob->obmat, ray_start, ray_normal, mval, loc, no, dist, &depth, 1); + + dm->release(dm); + } + + base= FIRSTBASE; + for ( base = FIRSTBASE; base != NULL; base = base->next ) { + if ( BASE_SELECTABLE(base) && ((mode == NOT_SELECTED && (base->flag & SELECT) == 0) || (mode == NOT_ACTIVE && base != BASACT)) ) { + Object *ob = base->object; + + if (ob->transflag & OB_DUPLI) + { + DupliObject *dupli_ob; + ListBase *lb = object_duplilist(G.scene, ob); + + for(dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) + { + Object *ob = dupli_ob->ob; + + if (ob->type == OB_MESH) { + DerivedMesh *dm = mesh_get_derived_final(ob, CD_MASK_BAREMESH); + int val; + + val = snapDerivedMesh(ob, dm, dupli_ob->mat, ray_start, ray_normal, mval, loc, no, dist, &depth, 0); + + retval = retval || val; + + dm->release(dm); } } + + free_object_duplilist(lb); + } + + if (ob->type == OB_MESH) { + DerivedMesh *dm = mesh_get_derived_final(ob, CD_MASK_BAREMESH); + int val; + + val = snapDerivedMesh(ob, dm, ob->obmat, ray_start, ray_normal, mval, loc, no, dist, &depth, 0); + + retval = retval || val; + + dm->release(dm); } } } |