Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/src/transform_snap.c')
-rw-r--r--source/blender/src/transform_snap.c617
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);
}
}
}