Merging volume embedding and transform snapping.

- Volume embed is available as a transform snap option (need new icon). Not as "continuous" as stroke embed, will have to be fixed somehow.
- Transform snaps work in armature edit mode (only snap to mesh, not other armatures, for now). Adding to other edit data type should be easy.
- Strokes can use all the transform snap options plus volume embed.

Bug fix: added small threshold to face snap (and volume embed) to prevent slipping in cracks between faces. More tweaking needed but this now takes care of all the worst cases.
This commit is contained in:
2009-02-24 00:45:40 +00:00
parent 7c830b75f1
commit 57c7200a65
7 changed files with 577 additions and 377 deletions

View File

@@ -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]);

View File

@@ -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)

View File

@@ -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

View File

@@ -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 */

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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);