diff --git a/source/blender/blenlib/BLI_arithb.h b/source/blender/blenlib/BLI_arithb.h index 6a2db92d25f..092ed00fbe5 100644 --- a/source/blender/blenlib/BLI_arithb.h +++ b/source/blender/blenlib/BLI_arithb.h @@ -394,6 +394,7 @@ int LineIntersectLine(float v1[3], float v2[3], float v3[3], float v4[3], float int LineIntersectLineStrict(float v1[3], float v2[3], float v3[3], float v4[3], float vi[3], float *lambda); int LineIntersectsTriangle(float p1[3], float p2[3], float v0[3], float v1[3], float v2[3], float *lambda, float *uv); int RayIntersectsTriangle(float p1[3], float d[3], float v0[3], float v1[3], float v2[3], float *lambda, float *uv); +int RayIntersectsTriangleThreshold(float p1[3], float d[3], float v0[3], float v1[3], float v2[3], float *lambda, float *uv, float threshold); int SweepingSphereIntersectsTriangleUV(float p1[3], float p2[3], float radius, float v0[3], float v1[3], float v2[3], float *lambda, float *ipoint); int AxialLineIntersectsTriangle(int axis, float co1[3], float co2[3], float v0[3], float v1[3], float v2[3], float *lambda); int AabbIntersectAabb(float min1[3], float max1[3], float min2[3], float max2[3]); diff --git a/source/blender/blenlib/intern/arithb.c b/source/blender/blenlib/intern/arithb.c index 5f94df6f5eb..ad1dc1ca12c 100644 --- a/source/blender/blenlib/intern/arithb.c +++ b/source/blender/blenlib/intern/arithb.c @@ -3896,6 +3896,57 @@ int RayIntersectsTriangle(float p1[3], float d[3], float v0[3], float v1[3], flo return 1; } +int RayIntersectsTriangleThreshold(float p1[3], float d[3], float v0[3], float v1[3], float v2[3], float *lambda, float *uv, float threshold) +{ + float p[3], s[3], e1[3], e2[3], q[3]; + float a, f, u, v; + float du = 0, dv = 0; + + VecSubf(e1, v1, v0); + VecSubf(e2, v2, v0); + + Crossf(p, d, e2); + a = Inpf(e1, p); + if ((a > -0.000001) && (a < 0.000001)) return 0; + f = 1.0f/a; + + VecSubf(s, p1, v0); + + Crossf(q, s, e1); + *lambda = f * Inpf(e2, q); + if ((*lambda < 0.0)) return 0; + + u = f * Inpf(s, p); + v = f * Inpf(d, q); + + if (u < 0) du = u; + if (u > 1) du = u - 1; + if (v < 0) dv = v; + if (v > 1) dv = v - 1; + if (u > 0 && v > 0 && u + v > 1) + { + float t = u + v - 1; + du = u - t/2; + dv = v - t/2; + } + + VecMulf(e1, du); + VecMulf(e2, dv); + + if (Inpf(e1, e1) + Inpf(e2, e2) > threshold * threshold) + { + return 0; + } + + if(uv) { + uv[0]= u; + uv[1]= v; + } + + return 1; +} + + /* Adapted from the paper by Kasper Fauerby */ /* "Improved Collision detection and Response" */ static int getLowestRoot(float a, float b, float c, float maxR, float* root) diff --git a/source/blender/include/BIF_transform.h b/source/blender/include/BIF_transform.h index 0e3985fc52c..8a8d7dc3b4a 100644 --- a/source/blender/include/BIF_transform.h +++ b/source/blender/include/BIF_transform.h @@ -86,6 +86,7 @@ struct TransInfo; struct ScrArea; struct Base; struct Scene; +struct Object; struct TransInfo * BIF_GetTransInfo(void); void BIF_setSingleAxisConstraint(float vec[3], char *text); @@ -125,5 +126,30 @@ void ManipulatorTransform(); int BIF_do_manipulator(struct ScrArea *sa); void BIF_draw_manipulator(struct ScrArea *sa); +/* Snapping */ + + +typedef struct DepthPeel +{ + struct DepthPeel *next, *prev; + + float depth; + float p[3]; + float no[3]; + struct Object *ob; + int flag; +} DepthPeel; + +struct ListBase; + +typedef enum SnapMode +{ + NOT_SELECTED = 0, + NOT_ACTIVE = 1 +} SnapMode; + +int snapObjects(int *dist, float *loc, float *no, SnapMode mode); +int peelObjects(struct ListBase *depth_peels, short mval[2]); + #endif diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index d04d3259c70..35e086b418a 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -752,6 +752,7 @@ typedef struct Scene { #define SCE_SNAP_MODE_VERTEX 0 #define SCE_SNAP_MODE_EDGE 1 #define SCE_SNAP_MODE_FACE 2 +#define SCE_SNAP_MODE_VOLUME 3 /* sce->selectmode */ #define SCE_SELECT_VERTEX 1 /* for mesh */ diff --git a/source/blender/src/editarmature_sketch.c b/source/blender/src/editarmature_sketch.c index 80302109b37..7314add5e7b 100644 --- a/source/blender/src/editarmature_sketch.c +++ b/source/blender/src/editarmature_sketch.c @@ -57,6 +57,8 @@ #include "BIF_generate.h" #include "BIF_interface.h" +#include "BIF_transform.h" + #include "blendef.h" #include "mydevice.h" #include "reeb.h" @@ -418,224 +420,6 @@ void BIF_setTemplate(int index) } } -/******************** PEELING *********************************/ - -typedef struct SK_DepthPeel -{ - struct SK_DepthPeel *next, *prev; - - float depth; - float p[3]; - float no[3]; - Object *ob; - int flag; -} SK_DepthPeel; - -int cmpPeel(void *arg1, void *arg2) -{ - SK_DepthPeel *p1 = arg1; - SK_DepthPeel *p2 = arg2; - int val = 0; - - if (p1->depth < p2->depth) - { - val = -1; - } - else if (p1->depth > p2->depth) - { - val = 1; - } - - return val; -} - -void addDepthPeel(ListBase *depth_peels, float depth, float p[3], float no[3], Object *ob) -{ - SK_DepthPeel *peel = MEM_callocN(sizeof(SK_DepthPeel), "DepthPeel"); - - peel->depth = depth; - peel->ob = ob; - VECCOPY(peel->p, p); - VECCOPY(peel->no, no); - - BLI_addtail(depth_peels, peel); - - peel->flag = 0; -} - -int peelDerivedMesh(Object *ob, DerivedMesh *dm, float obmat[][4], float ray_start[3], float ray_normal[3], short mval[2], ListBase *depth_peels) -{ - int retval = 0; - int totvert = dm->getNumVerts(dm); - int totface = dm->getNumFaces(dm); - - 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) { - MVert *verts = dm->getVertArray(dm); - MFace *faces = dm->getFaceArray(dm); - int i; - - for( i = 0; i < totface; i++) { - MFace *f = faces + i; - float lambda; - int result; - - - result = RayIntersectsTriangle(ray_start_local, ray_normal_local, verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, &lambda, NULL); - - if (result) { - float location[3], normal[3]; - float intersect[3]; - float new_depth; - - 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); - - Mat3MulVecfl(timat, normal); - Normalize(normal); - - addDepthPeel(depth_peels, new_depth, location, normal, ob); - } - - 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; - - 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); - - Mat3MulVecfl(timat, normal); - Normalize(normal); - - addDepthPeel(depth_peels, new_depth, location, normal, ob); - } - } - } - } - } - - return retval; -} - -int peelObjects(ListBase *depth_peels, short mval[2]) -{ - Base *base; - int retval = 0; - float ray_start[3], ray_normal[3]; - - viewray(mval, ray_start, ray_normal); - - base= FIRSTBASE; - for ( base = FIRSTBASE; base != NULL; base = base->next ) { - if ( BASE_SELECTABLE(base) ) { - 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 = peelDerivedMesh(ob, dm, dupli_ob->mat, ray_start, ray_normal, mval, depth_peels); - - retval = retval || val; - - dm->release(dm); - } - } - - free_object_duplilist(lb); - } - - if (ob->type == OB_MESH) { - DerivedMesh *dm = NULL; - int val; - - if (ob != G.obedit) - { - dm = mesh_get_derived_final(ob, CD_MASK_BAREMESH); - - val = peelDerivedMesh(ob, dm, ob->obmat, ray_start, ray_normal, mval, depth_peels); - } - else - { - dm = editmesh_get_derived_cage(CD_MASK_BAREMESH); - - val = peelDerivedMesh(ob, dm, ob->obmat, ray_start, ray_normal, mval, depth_peels); - } - - retval = retval || val; - - dm->release(dm); - } - } - } - - BLI_sortlist(depth_peels, cmpPeel); - - return retval; -} /*********************** CONVERSION ***************************/ void sk_autoname(ReebArc *arc) @@ -1087,6 +871,8 @@ void sk_filterStroke(SK_Stroke *stk, int start, int end) int nb_points = stk->nb_points; int i, j; + return; + if (start == -1) { start = 0; @@ -1783,99 +1569,120 @@ int sk_addStrokeSnapPoint(SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd) int sk_getStrokeEmbedPoint(SK_Point *pt, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd) { - ListBase depth_peels; - SK_DepthPeel *p1, *p2; - float *last_p = NULL; - float dist = FLT_MAX; - float p[3]; int point_added = 0; - - depth_peels.first = depth_peels.last = NULL; - - peelObjects(&depth_peels, dd->mval); - - if (stk->nb_points > 0 && stk->points[stk->nb_points - 1].type == PT_CONTINUOUS) - { - last_p = stk->points[stk->nb_points - 1].p; - } - else if (LAST_SNAP_POINT_VALID) - { - last_p = LAST_SNAP_POINT; - } - - - for (p1 = depth_peels.first; p1; p1 = p1->next) - { - if (p1->flag == 0) - { - float vec[3]; - float new_dist; - - p2 = NULL; - p1->flag = 1; - /* if peeling objects, take the first and last from each object */ - if (G.scene->snap_flag & SCE_SNAP_PEEL_OBJECT) + if (G.scene->snap_mode == SCE_SNAP_MODE_VOLUME) + { + ListBase depth_peels; + DepthPeel *p1, *p2; + float *last_p = NULL; + float dist = FLT_MAX; + float p[3]; + + depth_peels.first = depth_peels.last = NULL; + + peelObjects(&depth_peels, dd->mval); + + if (stk->nb_points > 0 && stk->points[stk->nb_points - 1].type == PT_CONTINUOUS) + { + last_p = stk->points[stk->nb_points - 1].p; + } + else if (LAST_SNAP_POINT_VALID) + { + last_p = LAST_SNAP_POINT; + } + + + for (p1 = depth_peels.first; p1; p1 = p1->next) + { + if (p1->flag == 0) { - SK_DepthPeel *peel; - for (peel = p1->next; peel; peel = peel->next) + float vec[3]; + float new_dist; + + p2 = NULL; + p1->flag = 1; + + /* if peeling objects, take the first and last from each object */ + if (G.scene->snap_flag & SCE_SNAP_PEEL_OBJECT) { - if (peel->ob == p1->ob) + DepthPeel *peel; + for (peel = p1->next; peel; peel = peel->next) { - peel->flag = 1; - p2 = peel; + if (peel->ob == p1->ob) + { + peel->flag = 1; + p2 = peel; + } } } - } - /* otherwise, pair first with second and so on */ - else - { - for (p2 = p1->next; p2 && p2->ob != p1->ob; p2 = p2->next) + /* otherwise, pair first with second and so on */ + else { - /* nothing to do here */ + for (p2 = p1->next; p2 && p2->ob != p1->ob; p2 = p2->next) + { + /* nothing to do here */ + } + } + + if (p2) + { + p2->flag = 1; + + VecAddf(vec, p1->p, p2->p); + VecMulf(vec, 0.5f); + } + else + { + VECCOPY(vec, p1->p); + } + + if (last_p == NULL) + { + VECCOPY(p, vec); + dist = 0; + break; + } + + new_dist = VecLenf(last_p, vec); + + if (new_dist < dist) + { + VECCOPY(p, vec); + dist = new_dist; } } + } + + if (dist != FLT_MAX) + { + pt->type = dd->type; + pt->mode = PT_EMBED; + VECCOPY(pt->p, p); - if (p2) - { - p2->flag = 1; - - VecAddf(vec, p1->p, p2->p); - VecMulf(vec, 0.5f); - } - else - { - VECCOPY(vec, p1->p); - } + point_added = 1; + } + + BLI_freelistN(&depth_peels); + } + else + { + float vec[3]; + float no[3]; + int found = 0; + int dist = 40; // Use a user defined value here + + found = snapObjects(&dist, vec, no, NOT_SELECTED); + if (found == 1) + { + pt->type = dd->type; + pt->mode = PT_EMBED; + VECCOPY(pt->p, vec); - if (last_p == NULL) - { - VECCOPY(p, vec); - dist = 0; - break; - } - - new_dist = VecLenf(last_p, vec); - - if (new_dist < dist) - { - VECCOPY(p, vec); - dist = new_dist; - } + point_added = 1; } } - if (dist != FLT_MAX) - { - pt->type = dd->type; - pt->mode = PT_EMBED; - VECCOPY(pt->p, p); - - point_added = 1; - } - - BLI_freelistN(&depth_peels); - return point_added; } diff --git a/source/blender/src/header_view3d.c b/source/blender/src/header_view3d.c index 878213e80a3..53be105f7a8 100644 --- a/source/blender/src/header_view3d.c +++ b/source/blender/src/header_view3d.c @@ -5218,6 +5218,7 @@ static char *snapmode_pup(void) str += sprintf(str, "%s", "|Vertex%x0"); str += sprintf(str, "%s", "|Edge%x1"); str += sprintf(str, "%s", "|Face%x2"); + str += sprintf(str, "%s", "|Volume%x3"); return string; } diff --git a/source/blender/src/transform_snap.c b/source/blender/src/transform_snap.c index eeb5eaeec10..1f21bda3b59 100644 --- a/source/blender/src/transform_snap.c +++ b/source/blender/src/transform_snap.c @@ -43,6 +43,7 @@ #include "BLI_arithb.h" #include "BLI_editVert.h" +#include "BLI_blenlib.h" #include "BDR_drawobject.h" @@ -57,6 +58,8 @@ #include "BIF_drawimage.h" #include "BIF_editmesh.h" +#include "BIF_transform.h" + #include "BKE_global.h" #include "BKE_utildefines.h" #include "BKE_DerivedMesh.h" @@ -91,11 +94,6 @@ float RotationBetween(TransInfo *t, float p1[3], float p2[3]); float TranslationBetween(TransInfo *t, float p1[3], float p2[3]); float ResizeBetween(TransInfo *t, float p1[3], float p2[3]); -/* Modes */ -#define NOT_SELECTED 0 -#define NOT_ACTIVE 1 -int snapObjects(int *dist, float *loc, float *no, int mode); - /****************** IMPLEMENTATIONS *********************/ @@ -103,7 +101,7 @@ int BIF_snappingSupported(void) { int status = 0; - if (G.obedit == NULL || G.obedit->type==OB_MESH) /* only support object or mesh */ + if (G.obedit == NULL || ELEM(G.obedit->type, OB_MESH, OB_ARMATURE)) /* only support object, mesh, armature */ { status = 1; } @@ -277,7 +275,7 @@ void initSnapping(TransInfo *t) /* Edit mode */ if (t->tsnap.applySnap != NULL && // A snapping function actually exist (G.scene->snap_flag & SCE_SNAP) && // Only if the snap flag is on - (G.obedit != NULL && G.obedit->type==OB_MESH) && // Temporary limited to edit mode meshes + (G.obedit != NULL && ELEM(G.obedit->type, OB_MESH, OB_ARMATURE)) && // Temporary limited to edit mode meshes and armatures ((t->flag & T_PROP_EDIT) == 0) ) // No PET, obviously { t->tsnap.status |= SNAP_ON; @@ -481,87 +479,167 @@ void CalcSnapGrid(TransInfo *t, float *vec) void CalcSnapGeometry(TransInfo *t, float *vec) { - /* Object mode */ - if (G.obedit == NULL) + if (t->spacetype == SPACE_VIEW3D) { - if (t->spacetype == SPACE_VIEW3D) + float loc[3]; + float no[3]; + int found = 0; + int dist = 40; // Use a user defined value here + SnapMode mode; + + if (G.scene->snap_mode == SCE_SNAP_MODE_VOLUME) { - float vec[3]; - float no[3]; - int found = 0; - int dist = 40; // Use a user defined value here + ListBase depth_peels; + DepthPeel *p1, *p2; + float *last_p = NULL; + float dist = FLT_MAX; + float p[3]; + short mval[2]; + + getmouseco_areawin(mval); - found = snapObjects(&dist, vec, no, NOT_SELECTED); - if (found == 1) + depth_peels.first = depth_peels.last = NULL; + + peelObjects(&depth_peels, mval); + +// if (stk->nb_points > 0 && stk->points[stk->nb_points - 1].type == PT_CONTINUOUS) +// { +// last_p = stk->points[stk->nb_points - 1].p; +// } +// else if (LAST_SNAP_POINT_VALID) +// { +// last_p = LAST_SNAP_POINT; +// } + + + for (p1 = depth_peels.first; p1; p1 = p1->next) { - float tangent[3]; - - VecSubf(tangent, vec, t->tsnap.snapPoint); - tangent[2] = 0; - - if (Inpf(tangent, tangent) > 0) + if (p1->flag == 0) { - VECCOPY(t->tsnap.snapTangent, tangent); + float vec[3]; + float new_dist; + + p2 = NULL; + p1->flag = 1; + + /* if peeling objects, take the first and last from each object */ + if (G.scene->snap_flag & SCE_SNAP_PEEL_OBJECT) + { + DepthPeel *peel; + for (peel = p1->next; peel; peel = peel->next) + { + if (peel->ob == p1->ob) + { + peel->flag = 1; + p2 = peel; + } + } + } + /* otherwise, pair first with second and so on */ + else + { + for (p2 = p1->next; p2 && p2->ob != p1->ob; p2 = p2->next) + { + /* nothing to do here */ + } + } + + if (p2) + { + p2->flag = 1; + + VecAddf(vec, p1->p, p2->p); + VecMulf(vec, 0.5f); + } + else + { + VECCOPY(vec, p1->p); + } + + if (last_p == NULL) + { + VECCOPY(p, vec); + dist = 0; + break; + } + + new_dist = VecLenf(last_p, vec); + + if (new_dist < dist) + { + VECCOPY(p, vec); + dist = new_dist; + } } - - VECCOPY(t->tsnap.snapPoint, vec); - VECCOPY(t->tsnap.snapNormal, no); - - t->tsnap.status |= POINT_INIT; + } + + if (dist != FLT_MAX) + { + VECCOPY(loc, p); + found = 1; + } + + BLI_freelistN(&depth_peels); + } + else + { + if (G.obedit == NULL) + { + mode = NOT_SELECTED; } else { - t->tsnap.status &= ~POINT_INIT; + mode = NOT_ACTIVE; } + + found = snapObjects(&dist, loc, no, NOT_SELECTED); + } + + if (found == 1) + { + float tangent[3]; + + VecSubf(tangent, loc, t->tsnap.snapPoint); + tangent[2] = 0; + + if (Inpf(tangent, tangent) > 0) + { + VECCOPY(t->tsnap.snapTangent, tangent); + } + + VECCOPY(t->tsnap.snapPoint, loc); + VECCOPY(t->tsnap.snapNormal, no); + + t->tsnap.status |= POINT_INIT; + } + else + { + t->tsnap.status &= ~POINT_INIT; } } - /* Mesh edit mode */ - else if (G.obedit != NULL && G.obedit->type==OB_MESH) - { - if (t->spacetype == SPACE_VIEW3D) + else if (t->spacetype == SPACE_IMAGE && G.obedit != NULL && G.obedit->type==OB_MESH) + { /* same as above but for UV's */ + MTFace *nearesttf=NULL; + float aspx, aspy; + int face_corner; + + find_nearest_uv(&nearesttf, NULL, NULL, &face_corner); + + if (nearesttf != NULL) { - float vec[3]; - float no[3]; - int found = 0; - int dist = 40; // Use a user defined value here + VECCOPY2D(t->tsnap.snapPoint, nearesttf->uv[face_corner]); - found = snapObjects(&dist, vec, no, NOT_ACTIVE); - if (found == 1) - { - VECCOPY(t->tsnap.snapPoint, vec); - VECCOPY(t->tsnap.snapNormal, no); - - t->tsnap.status |= POINT_INIT; - } - else - { - t->tsnap.status &= ~POINT_INIT; - } - } - else if (t->spacetype == SPACE_IMAGE) - { /* same as above but for UV's */ - MTFace *nearesttf=NULL; - float aspx, aspy; - int face_corner; + transform_aspect_ratio_tface_uv(&aspx, &aspy); + t->tsnap.snapPoint[0] *= aspx; + t->tsnap.snapPoint[1] *= aspy; + + //Mat4MulVecfl(G.obedit->obmat, t->tsnap.snapPoint); - find_nearest_uv(&nearesttf, NULL, NULL, &face_corner); - - if (nearesttf != NULL) - { - VECCOPY2D(t->tsnap.snapPoint, nearesttf->uv[face_corner]); - - transform_aspect_ratio_tface_uv(&aspx, &aspy); - t->tsnap.snapPoint[0] *= aspx; - t->tsnap.snapPoint[1] *= aspy; - - //Mat4MulVecfl(G.obedit->obmat, t->tsnap.snapPoint); - - t->tsnap.status |= POINT_INIT; - } - else - { - t->tsnap.status &= ~POINT_INIT; - } + t->tsnap.status |= POINT_INIT; + } + else + { + t->tsnap.status &= ~POINT_INIT; } } } @@ -824,7 +902,7 @@ int snapDerivedMesh(Object *ob, DerivedMesh *dm, float obmat[][4], float ray_sta if (test) { - result = RayIntersectsTriangle(ray_start_local, ray_normal_local, verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, &lambda, NULL); + result = RayIntersectsTriangleThreshold(ray_start_local, ray_normal_local, verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, &lambda, NULL, 0.001); if (result) { float location[3], normal[3]; @@ -868,7 +946,7 @@ int snapDerivedMesh(Object *ob, DerivedMesh *dm, float obmat[][4], float ray_sta 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); + result = RayIntersectsTriangleThreshold(ray_start_local, ray_normal_local, verts[f->v3].co, verts[f->v4].co, verts[f->v1].co, &lambda, NULL, 0.001); if (result) { float location[3], normal[3]; @@ -1149,7 +1227,7 @@ int snapDerivedMesh(Object *ob, DerivedMesh *dm, float obmat[][4], float ray_sta return retval; } -int snapObjects(int *dist, float *loc, float *no, int mode) { +int snapObjects(int *dist, float *loc, float *no, SnapMode mode) { Base *base; float depth = FLT_MAX; int retval = 0; @@ -1164,11 +1242,14 @@ int snapObjects(int *dist, float *loc, float *no, int mode) { 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); + if (ob->type == OB_MESH) + { + 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; @@ -1227,6 +1308,238 @@ int snapObjects(int *dist, float *loc, float *no, int mode) { return retval; } +/******************** PEELING *********************************/ + + +int cmpPeel(void *arg1, void *arg2) +{ + DepthPeel *p1 = arg1; + DepthPeel *p2 = arg2; + int val = 0; + + if (p1->depth < p2->depth) + { + val = -1; + } + else if (p1->depth > p2->depth) + { + val = 1; + } + + return val; +} + +void removeDoublesPeel(ListBase *depth_peels) +{ + DepthPeel *peel; + + for (peel = depth_peels->first; peel; peel = peel->next) + { + DepthPeel *next_peel = peel->next; + + if (peel && next_peel && ABS(peel->depth - next_peel->depth) < 0.0015) + { + peel->next = next_peel->next; + + if (next_peel->next) + { + next_peel->next->prev = peel; + } + + MEM_freeN(next_peel); + } + } +} + +void addDepthPeel(ListBase *depth_peels, float depth, float p[3], float no[3], Object *ob) +{ + DepthPeel *peel = MEM_callocN(sizeof(DepthPeel), "DepthPeel"); + + peel->depth = depth; + peel->ob = ob; + VECCOPY(peel->p, p); + VECCOPY(peel->no, no); + + BLI_addtail(depth_peels, peel); + + peel->flag = 0; +} + +int peelDerivedMesh(Object *ob, DerivedMesh *dm, float obmat[][4], float ray_start[3], float ray_normal[3], short mval[2], ListBase *depth_peels) +{ + int retval = 0; + int totvert = dm->getNumVerts(dm); + int totface = dm->getNumFaces(dm); + + 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) { + MVert *verts = dm->getVertArray(dm); + MFace *faces = dm->getFaceArray(dm); + int i; + + for( i = 0; i < totface; i++) { + MFace *f = faces + i; + float lambda; + int result; + + + result = RayIntersectsTriangleThreshold(ray_start_local, ray_normal_local, verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, &lambda, NULL, 0.001); + + if (result) { + float location[3], normal[3]; + float intersect[3]; + float new_depth; + + 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); + + Mat3MulVecfl(timat, normal); + Normalize(normal); + + addDepthPeel(depth_peels, new_depth, location, normal, ob); + } + + if (f->v4 && result == 0) + { + result = RayIntersectsTriangleThreshold(ray_start_local, ray_normal_local, verts[f->v3].co, verts[f->v4].co, verts[f->v1].co, &lambda, NULL, 0.001); + + if (result) { + float location[3], normal[3]; + float intersect[3]; + float new_depth; + + 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); + + Mat3MulVecfl(timat, normal); + Normalize(normal); + + addDepthPeel(depth_peels, new_depth, location, normal, ob); + } + } + } + } + } + + return retval; +} + +int peelObjects(ListBase *depth_peels, short mval[2]) +{ + Base *base; + int retval = 0; + float ray_start[3], ray_normal[3]; + + viewray(mval, ray_start, ray_normal); + + base= FIRSTBASE; + for ( base = FIRSTBASE; base != NULL; base = base->next ) { + if ( BASE_SELECTABLE(base) ) { + 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 = peelDerivedMesh(ob, dm, dupli_ob->mat, ray_start, ray_normal, mval, depth_peels); + + retval = retval || val; + + dm->release(dm); + } + } + + free_object_duplilist(lb); + } + + if (ob->type == OB_MESH) { + DerivedMesh *dm = NULL; + int val; + + if (ob != G.obedit) + { + dm = mesh_get_derived_final(ob, CD_MASK_BAREMESH); + + val = peelDerivedMesh(ob, dm, ob->obmat, ray_start, ray_normal, mval, depth_peels); + } + else + { + dm = editmesh_get_derived_cage(CD_MASK_BAREMESH); + + val = peelDerivedMesh(ob, dm, ob->obmat, ray_start, ray_normal, mval, depth_peels); + } + + retval = retval || val; + + dm->release(dm); + } + } + } + + BLI_sortlist(depth_peels, cmpPeel); + removeDoublesPeel(depth_peels); + + return retval; +} + /*================================================================*/ static void applyGrid(TransInfo *t, float *val, int max_index, float fac[3], GearsType action);