diff options
-rw-r--r-- | source/blender/blenkernel/BKE_DerivedMesh.h | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_bvhutils.h | 45 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_shrinkwrap.h | 4 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/DerivedMesh.c | 5 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/bvhutils.c | 196 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/constraint.c | 162 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/shrinkwrap.c | 257 | ||||
-rw-r--r-- | source/blender/blenloader/intern/readfile.c | 13 | ||||
-rw-r--r-- | source/blender/include/butspace.h | 1 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_constraint_types.h | 12 | ||||
-rw-r--r-- | source/blender/src/buttons_editing.c | 14 | ||||
-rw-r--r-- | source/blender/src/buttons_object.c | 40 | ||||
-rw-r--r-- | source/blender/src/editconstraint.c | 5 |
13 files changed, 568 insertions, 188 deletions
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h index 5a1e266adeb..263b17151e7 100644 --- a/source/blender/blenkernel/BKE_DerivedMesh.h +++ b/source/blender/blenkernel/BKE_DerivedMesh.h @@ -44,6 +44,7 @@ #include "DNA_customdata_types.h" #include "BKE_customdata.h" +#include "BKE_bvhutils.h" struct MVert; struct MEdge; @@ -69,6 +70,7 @@ struct DerivedMesh { int numVertData, numEdgeData, numFaceData; int needsFree; /* checked on ->release, is set to 0 for cached results */ int deformedOnly; /* set by modifier stack if only deformed from original */ + BVHCache bvhCache; /* Misc. Queries */ diff --git a/source/blender/blenkernel/BKE_bvhutils.h b/source/blender/blenkernel/BKE_bvhutils.h index dd9ea61f24b..66c8d99959a 100644 --- a/source/blender/blenkernel/BKE_bvhutils.h +++ b/source/blender/blenkernel/BKE_bvhutils.h @@ -31,6 +31,7 @@ #define BKE_BVHUTILS_H #include "BLI_kdopbvh.h" +#include "BLI_linklist.h" /* * This header encapsulates necessary code to buld a BVH @@ -52,7 +53,7 @@ typedef struct BVHTreeFromMesh BVHTree_RayCastCallback raycast_callback; /* Mesh represented on this BVHTree */ - struct DerivedMesh *mesh; + struct DerivedMesh *mesh; /* Vertex array, so that callbacks have instante access to data */ struct MVert *vert; @@ -61,6 +62,9 @@ typedef struct BVHTreeFromMesh /* radius for raycast */ float sphere_radius; + /* Private data */ + int cached; + } BVHTreeFromMesh; /* @@ -74,7 +78,7 @@ typedef struct BVHTreeFromMesh * * free_bvhtree_from_mesh should be called when the tree is no longer needed. */ -void bvhtree_from_mesh_verts(struct BVHTreeFromMesh *data, struct DerivedMesh *mesh, float epsilon, int tree_type, int axis); +BVHTree* bvhtree_from_mesh_verts(struct BVHTreeFromMesh *data, struct DerivedMesh *mesh, float epsilon, int tree_type, int axis); /* * Builds a bvh tree where nodes are the faces of the given mesh. @@ -84,15 +88,50 @@ void bvhtree_from_mesh_verts(struct BVHTreeFromMesh *data, struct DerivedMesh *m * so that the coordinates and rays are first translated on the mesh local coordinates. * Reason for this is that later bvh_from_mesh_* might use a cache system and so it becames possible to reuse * a BVHTree. + * + * The returned value is the same as in data->tree, its only returned to make it easier to test + * the success * * free_bvhtree_from_mesh should be called when the tree is no longer needed. */ -void bvhtree_from_mesh_faces(struct BVHTreeFromMesh *data, struct DerivedMesh *mesh, float epsilon, int tree_type, int axis); +BVHTree* bvhtree_from_mesh_faces(struct BVHTreeFromMesh *data, struct DerivedMesh *mesh, float epsilon, int tree_type, int axis); /* * Frees data allocated by a call to bvhtree_from_mesh_*. */ void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data); + +/* + * BVHCache + */ + +//Using local coordinates +#define BVHTREE_FROM_FACES 0 +#define BVHTREE_FROM_VERTICES 1 + +typedef LinkNode* BVHCache; + + +/* + * Queries a bvhcache for the chache bvhtree of the request type + */ +BVHTree *bvhcache_find(BVHCache *cache, int type); + +/* + * Inserts a BVHTree of the given type under the cache + * After that the caller no longer needs to worry when to free the BVHTree + * as that will be done when the cache is freed. + * + * A call to this assumes that there was no previous cached tree of the given type + */ +void bvhcache_insert(BVHCache *cache, BVHTree *tree, int type); + +/* + * inits and frees a bvhcache + */ +void bvhcache_init(BVHCache *cache); +void bvhcache_free(BVHCache *cache); + #endif diff --git a/source/blender/blenkernel/BKE_shrinkwrap.h b/source/blender/blenkernel/BKE_shrinkwrap.h index eed22ff9d8e..6ce449f7824 100644 --- a/source/blender/blenkernel/BKE_shrinkwrap.h +++ b/source/blender/blenkernel/BKE_shrinkwrap.h @@ -95,6 +95,8 @@ void space_transform_invert_normal(const SpaceTransform *data, float *no); struct Object; struct DerivedMesh; +struct MVert; +struct MDeformVert; struct ShrinkwrapModifierData; struct MDeformVert; struct BVHTree; @@ -105,8 +107,8 @@ typedef struct ShrinkwrapCalcData ShrinkwrapModifierData *smd; //shrinkwrap modifier data struct Object *ob; //object we are applying shrinkwrap to - struct DerivedMesh *original; //mesh before shrinkwrap + MVert *vert; //Array of verts being projected (to fetch normals or other data) float (*vertexCos)[3]; //vertexs being shrinkwraped int numVerts; diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index c934f7d9fe7..d43cbdebe72 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -77,6 +77,7 @@ #include "BKE_texture.h" #include "BKE_utildefines.h" #include "BKE_particle.h" +#include "BKE_bvhutils.h" #include "BLO_sys_types.h" // for intptr_t support @@ -182,6 +183,8 @@ void DM_init_funcs(DerivedMesh *dm) dm->getVertDataArray = DM_get_vert_data_layer; dm->getEdgeDataArray = DM_get_edge_data_layer; dm->getFaceDataArray = DM_get_face_data_layer; + + bvhcache_init(&dm->bvhCache); } void DM_init(DerivedMesh *dm, @@ -218,6 +221,8 @@ void DM_from_template(DerivedMesh *dm, DerivedMesh *source, int DM_release(DerivedMesh *dm) { if (dm->needsFree) { + bvhcache_free(&dm->bvhCache); + CustomData_free(&dm->vertData, dm->numVertData); CustomData_free(&dm->edgeData, dm->numEdgeData); CustomData_free(&dm->faceData, dm->numFaceData); diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c index ae449843d2a..d9e005811d0 100644 --- a/source/blender/blenkernel/intern/bvhutils.c +++ b/source/blender/blenkernel/intern/bvhutils.c @@ -30,6 +30,7 @@ #include <stdio.h> #include <string.h> #include <math.h> +#include <assert.h> #include "BKE_bvhutils.h" @@ -45,6 +46,8 @@ #include "BKE_global.h" #include "BLI_arithb.h" +#include "BLI_linklist.h" +#include "MEM_guardedalloc.h" /* Math stuff for ray casting on mesh faces and for nearest surface */ @@ -480,30 +483,47 @@ static void mesh_faces_spherecast(void *userdata, int index, const BVHTreeRay *r * BVH builders */ // Builds a bvh tree.. where nodes are the vertexs of the given mesh -void bvhtree_from_mesh_verts(BVHTreeFromMesh *data, DerivedMesh *mesh, float epsilon, int tree_type, int axis) +BVHTree* bvhtree_from_mesh_verts(BVHTreeFromMesh *data, DerivedMesh *mesh, float epsilon, int tree_type, int axis) { - int i; - int numVerts= mesh->getNumVerts(mesh); - MVert *vert = mesh->getVertDataArray(mesh, CD_MVERT); - BVHTree *tree = NULL; + BVHTree *tree = bvhcache_find(&mesh->bvhCache, BVHTREE_FROM_VERTICES); - memset(data, 0, sizeof(*data)); + //Not in cache + if(tree == NULL) + { + int i; + int numVerts= mesh->getNumVerts(mesh); + MVert *vert = mesh->getVertDataArray(mesh, CD_MVERT); - if(vert == NULL) + if(vert != NULL) + { + tree = BLI_bvhtree_new(numVerts, epsilon, tree_type, axis); + + if(tree != NULL) + { + for(i = 0; i < numVerts; i++) + BLI_bvhtree_insert(tree, i, vert[i].co, 1); + + BLI_bvhtree_balance(tree); + + //Save on cache for later use +// printf("BVHTree built and saved on cache\n"); + bvhcache_insert(&mesh->bvhCache, tree, BVHTREE_FROM_VERTICES); + } + } + } + else { - printf("bvhtree cant be build: cant get a vertex array"); - return; +// printf("BVHTree is already build, using cached tree\n"); } - tree = BLI_bvhtree_new(numVerts, epsilon, tree_type, axis); - if(tree != NULL) - { - for(i = 0; i < numVerts; i++) - BLI_bvhtree_insert(tree, i, vert[i].co, 1); - BLI_bvhtree_balance(tree); + //Setup BVHTreeFromMesh + memset(data, 0, sizeof(*data)); + data->tree = tree; - data->tree = tree; + if(data->tree) + { + data->cached = TRUE; //a NULL nearest callback works fine //remeber the min distance to point is the same as the min distance to BV of point @@ -516,43 +536,62 @@ void bvhtree_from_mesh_verts(BVHTreeFromMesh *data, DerivedMesh *mesh, float eps data->sphere_radius = epsilon; } + + return data->tree; } // Builds a bvh tree.. where nodes are the faces of the given mesh. -void bvhtree_from_mesh_faces(BVHTreeFromMesh *data, DerivedMesh *mesh, float epsilon, int tree_type, int axis) +BVHTree* bvhtree_from_mesh_faces(BVHTreeFromMesh *data, DerivedMesh *mesh, float epsilon, int tree_type, int axis) { - int i; - int numFaces= mesh->getNumFaces(mesh); - MVert *vert = mesh->getVertDataArray(mesh, CD_MVERT); - MFace *face = mesh->getFaceDataArray(mesh, CD_MFACE); - BVHTree *tree = NULL; - - memset(data, 0, sizeof(*data)); + BVHTree *tree = bvhcache_find(&mesh->bvhCache, BVHTREE_FROM_FACES); - if(vert == NULL && face == NULL) + //Not in cache + if(tree == NULL) { - printf("bvhtree cant be build: cant get a vertex/face array"); - return; - } + int i; + int numFaces= mesh->getNumFaces(mesh); + MVert *vert = mesh->getVertDataArray(mesh, CD_MVERT); + MFace *face = mesh->getFaceDataArray(mesh, CD_MFACE); - /* Create a bvh-tree of the given target */ - tree = BLI_bvhtree_new(numFaces, epsilon, tree_type, axis); - if(tree != NULL) - { - for(i = 0; i < numFaces; i++) + if(vert != NULL && face != NULL) { - float co[4][3]; - VECCOPY(co[0], vert[ face[i].v1 ].co); - VECCOPY(co[1], vert[ face[i].v2 ].co); - VECCOPY(co[2], vert[ face[i].v3 ].co); - if(face[i].v4) - VECCOPY(co[3], vert[ face[i].v4 ].co); + /* Create a bvh-tree of the given target */ + tree = BLI_bvhtree_new(numFaces, epsilon, tree_type, axis); + if(tree != NULL) + { + for(i = 0; i < numFaces; i++) + { + float co[4][3]; + VECCOPY(co[0], vert[ face[i].v1 ].co); + VECCOPY(co[1], vert[ face[i].v2 ].co); + VECCOPY(co[2], vert[ face[i].v3 ].co); + if(face[i].v4) + VECCOPY(co[3], vert[ face[i].v4 ].co); - BLI_bvhtree_insert(tree, i, co[0], face[i].v4 ? 4 : 3); + BLI_bvhtree_insert(tree, i, co[0], face[i].v4 ? 4 : 3); + } + BLI_bvhtree_balance(tree); + + //Save on cache for later use +// printf("BVHTree built and saved on cache\n"); + bvhcache_insert(&mesh->bvhCache, tree, BVHTREE_FROM_FACES); + } } - BLI_bvhtree_balance(tree); + } + else + { +// printf("BVHTree is already build, using cached tree\n"); + } + + + //Setup BVHTreeFromMesh + memset(data, 0, sizeof(*data)); + data->tree = tree; + + if(data->tree) + { + data->cached = TRUE; - data->tree = tree; data->nearest_callback = mesh_faces_nearest_point; data->raycast_callback = mesh_faces_spherecast; @@ -562,6 +601,8 @@ void bvhtree_from_mesh_faces(BVHTreeFromMesh *data, DerivedMesh *mesh, float eps data->sphere_radius = epsilon; } + return data->tree; + } // Frees data allocated by a call to bvhtree_from_mesh_*. @@ -569,9 +610,78 @@ void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data) { if(data->tree) { - BLI_bvhtree_free(data->tree); + if(!data->cached) + BLI_bvhtree_free(data->tree); + memset( data, 0, sizeof(data) ); } } +/* BVHCache */ +typedef struct BVHCacheItem +{ + int type; + BVHTree *tree; + +} BVHCacheItem; + +static void bvhcacheitem_set_if_match(void *_cached, void *_search) +{ + BVHCacheItem * cached = (BVHCacheItem *)_cached; + BVHCacheItem * search = (BVHCacheItem *)_search; + + if(search->type == cached->type) + { + search->tree = cached->tree; + } +} + +BVHTree *bvhcache_find(BVHCache *cache, int type) +{ + BVHCacheItem item; + item.type = type; + item.tree = NULL; + + BLI_linklist_apply(*cache, bvhcacheitem_set_if_match, &item); + return item.tree; +} + +void bvhcache_insert(BVHCache *cache, BVHTree *tree, int type) +{ + BVHCacheItem *item = NULL; + + assert( tree != NULL ); + assert( bvhcache_find(cache, type) == NULL ); + + item = MEM_mallocN(sizeof(BVHCacheItem), "BVHCacheItem"); + assert( item != NULL ); + + item->type = type; + item->tree = tree; + + BLI_linklist_prepend( cache, item ); +} + + +void bvhcache_init(BVHCache *cache) +{ + *cache = NULL; +} + +static void bvhcacheitem_free(void *_item) +{ + BVHCacheItem *item = (BVHCacheItem *)_item; + + BLI_bvhtree_free(item->tree); + MEM_freeN(item); +} + + +void bvhcache_free(BVHCache *cache) +{ + BLI_linklist_free(*cache, (LinkNodeFreeFP)bvhcacheitem_free); + *cache = NULL; +} + + diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index db98c200566..f93fc403404 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -40,6 +40,7 @@ #include "DNA_armature_types.h" #include "DNA_constraint_types.h" +#include "DNA_modifier_types.h" #include "DNA_object_types.h" #include "DNA_action_types.h" #include "DNA_curve_types.h" @@ -63,6 +64,7 @@ #include "BKE_global.h" #include "BKE_library.h" #include "BKE_idprop.h" +#include "BKE_shrinkwrap.h" #ifndef DISABLE_PYTHON #include "BPY_extern.h" @@ -3239,6 +3241,165 @@ static bConstraintTypeInfo CTI_TRANSFORM = { transform_evaluate /* evaluate */ }; +/* ---------- Shrinkwrap Constraint ----------- */ + +static int shrinkwrap_get_tars (bConstraint *con, ListBase *list) +{ + if (con && list) { + bShrinkwrapConstraint *data = con->data; + bConstraintTarget *ct; + + SINGLETARGETNS_GET_TARS(con, data->target, ct, list) + + return 1; + } + + return 0; +} + + +static void shrinkwrap_flush_tars (bConstraint *con, ListBase *list, short nocopy) +{ + if (con && list) { + bShrinkwrapConstraint *data = con->data; + bConstraintTarget *ct= list->first; + + SINGLETARGETNS_FLUSH_TARS(con, data->target, ct, list, nocopy) + } +} + + +static void shrinkwrap_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float ctime) +{ + bShrinkwrapConstraint *scon = (bShrinkwrapConstraint *) con->data; + + if( VALID_CONS_TARGET(ct) && (ct->tar->type == OB_MESH) ) + { + int fail = FALSE; + float co[3] = {0.0f, 0.0f, 0.0f}; + float no[3] = {0.0f, 0.0f, 0.0f}; + float dist; + + SpaceTransform transform; + DerivedMesh *target = object_get_derived_final(ct->tar, CD_MASK_BAREMESH); + BVHTreeRayHit hit; + BVHTreeNearest nearest; + + BVHTreeFromMesh treeData; + memset( &treeData, 0, sizeof(treeData) ); + + nearest.index = -1; + nearest.dist = FLT_MAX; + + hit.index = -1; + hit.dist = 100000.0f; //TODO should use FLT_MAX.. but normal projection doenst yet supports it + + Mat4One(ct->matrix); + + if(target != NULL) + { + space_transform_from_matrixs(&transform, cob->matrix, ct->tar->obmat); + + switch(scon->shrinkType) + { + case MOD_SHRINKWRAP_NEAREST_SURFACE: + case MOD_SHRINKWRAP_NEAREST_VERTEX: + + if(scon->shrinkType == MOD_SHRINKWRAP_NEAREST_VERTEX) + bvhtree_from_mesh_verts(&treeData, target, 0.0, 2, 6); + else + bvhtree_from_mesh_faces(&treeData, target, 0.0, 2, 6); + + if(treeData.tree == NULL) + { + fail = TRUE; + break; + } + + space_transform_apply(&transform, co); + + BLI_bvhtree_find_nearest(treeData.tree, co, &nearest, treeData.nearest_callback, &treeData); + + dist = VecLenf(co, nearest.co); + VecLerpf(co, co, nearest.co, (dist - scon->dist)/dist); /* linear interpolation */ + space_transform_invert(&transform, co); + break; + + case MOD_SHRINKWRAP_PROJECT: + if(scon->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_X_AXIS) no[0] = 1.0f; + if(scon->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_Y_AXIS) no[1] = 1.0f; + if(scon->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_Z_AXIS) no[2] = 1.0f; + + if(INPR(no,no) < FLT_EPSILON) + { + fail = TRUE; + break; + } + + Normalize(no); + + + bvhtree_from_mesh_faces(&treeData, target, scon->dist, 4, 6); + if(treeData.tree == NULL) + { + fail = TRUE; + break; + } + + if(normal_projection_project_vertex(0, co, no, &transform, treeData.tree, &hit, treeData.raycast_callback, &treeData) == FALSE) + { + fail = TRUE; + break; + } + VECCOPY(co, hit.co); + break; + } + + free_bvhtree_from_mesh(&treeData); + + target->release(target); + + if(fail == TRUE) + { + /* Don't move the point */ + co[0] = co[1] = co[2] = 0.0f; + } + + /* co is in local object coordinates, change it to global and update target position */ + VecMat4MulVecfl(co, cob->matrix, co); + VECCOPY(ct->matrix[3], co); + } + } +} + +static void shrinkwrap_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets) +{ + bConstraintTarget *ct= targets->first; + + /* only evaluate if there is a target */ + if (VALID_CONS_TARGET(ct)) + { + VECCOPY(cob->matrix[3], ct->matrix[3]); + } +} + +static bConstraintTypeInfo CTI_SHRINKWRAP = { + CONSTRAINT_TYPE_SHRINKWRAP, /* type */ + sizeof(bShrinkwrapConstraint), /* size */ + "Shrinkwrap", /* name */ + "bShrinkwrapConstraint", /* struct name */ + NULL, /* free data */ + NULL, /* relink data */ + NULL, /* copy data */ + NULL, /* new data */ + shrinkwrap_get_tars, /* get constraint targets */ + shrinkwrap_flush_tars, /* flush constraint targets */ + shrinkwrap_get_tarmat, /* get a target matrix */ + shrinkwrap_evaluate /* evaluate */ +}; + + + /* ************************* Constraints Type-Info *************************** */ /* All of the constraints api functions use bConstraintTypeInfo structs to carry out * and operations that involve constraint specifc code. @@ -3270,6 +3431,7 @@ static void constraints_init_typeinfo () { constraintsTypeInfo[17]= &CTI_RIGIDBODYJOINT; /* RigidBody Constraint */ constraintsTypeInfo[18]= &CTI_CLAMPTO; /* ClampTo Constraint */ constraintsTypeInfo[19]= &CTI_TRANSFORM; /* Transformation Constraint */ + constraintsTypeInfo[20]= &CTI_SHRINKWRAP; /* Shrinkwrap Constraint */ } /* This function should be used for getting the appropriate type-info when only diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c index ab98fb1f007..6784f014efa 100644 --- a/source/blender/blenkernel/intern/shrinkwrap.c +++ b/source/blender/blenkernel/intern/shrinkwrap.c @@ -148,6 +148,7 @@ static float squared_dist(const float *a, const float *b) void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedMesh *dm, float (*vertexCos)[3], int numVerts) { + DerivedMesh *ss_mesh = NULL; ShrinkwrapCalcData calc = NULL_ShrinkwrapCalcData; //remove loop dependencies on derived meshs (TODO should this be done elsewhere?) @@ -158,15 +159,14 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedM //Configure Shrinkwrap calc data calc.smd = smd; calc.ob = ob; - calc.original = dm; calc.numVerts = numVerts; calc.vertexCos = vertexCos; //DeformVertex calc.vgroup = get_named_vertexgroup_num(calc.ob, calc.smd->vgroup_name); - if(calc.original) + if(dm) { - calc.dvert = calc.original->getVertDataArray(calc.original, CD_MDEFORMVERT); + calc.dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); } else if(calc.ob->type == OB_LATTICE) { @@ -176,17 +176,54 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedM if(smd->target) { - //TODO currently we need a copy in case object_get_derived_final returns an emDM that does not defines getVertArray or getFace array - calc.target = CDDM_copy( object_get_derived_final(smd->target, CD_MASK_BAREMESH) ); + calc.target = object_get_derived_final(smd->target, CD_MASK_BAREMESH); - //TODO there might be several "bugs" on non-uniform scales matrixs.. because it will no longer be nearest surface, not sphere projection + //TODO there might be several "bugs" on non-uniform scales matrixs + //because it will no longer be nearest surface, not sphere projection //because space has been deformed space_transform_setup(&calc.local2target, ob, smd->target); - calc.keepDist = smd->keepDist; //TODO: smd->keepDist is in global units.. must change to local + //TODO: smd->keepDist is in global units.. must change to local + calc.keepDist = smd->keepDist; } + + calc.vgroup = get_named_vertexgroup_num(calc.ob, smd->vgroup_name); + + if(dm != NULL) + { + //Setup arrays to get vertexs positions, normals and deform weights + calc.vert = dm->getVertDataArray(dm, CD_MVERT); + calc.dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); + + //Using vertexs positions/normals as if a subsurface was applied + if(smd->subsurfLevels) + { + SubsurfModifierData ssmd; + memset(&ssmd, 0, sizeof(ssmd)); + ssmd.subdivType = ME_CC_SUBSURF; //catmull clark + ssmd.levels = smd->subsurfLevels; //levels + + ss_mesh = subsurf_make_derived_from_derived(dm, &ssmd, FALSE, NULL, 0, 0); + + if(ss_mesh) + { + calc.vert = ss_mesh->getVertDataArray(ss_mesh, CD_MVERT); + if(calc.vert) + { + //TRICKY: this code assumes subsurface will have the transformed original vertices + //in their original order at the end of the vert array. + calc.vert = calc.vert + ss_mesh->getNumVerts(ss_mesh) - dm->getNumVerts(dm); + } + } + + //Just to make sure we are not letting any memory behind + assert(ssmd.emCache == NULL); + assert(ssmd.mCache == NULL); + } + } + //Projecting target defined - lets work! if(calc.target) { @@ -207,8 +244,8 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedM } //free memory - if(calc.target) - calc.target->release( calc.target ); + if(ss_mesh) + ss_mesh->release(ss_mesh); } /* @@ -244,8 +281,17 @@ void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc) float weight = vertexgroup_get_vertex_weight(calc->dvert, i, calc->vgroup); if(weight == 0.0f) continue; - VECCOPY(tmp_co, co); - space_transform_apply(&calc->local2target, tmp_co); //Convert the coordinates to the tree coordinates + + //Convert the vertex to tree coordinates + if(calc->vert) + { + VECCOPY(tmp_co, calc->vert[i].co); + } + else + { + VECCOPY(tmp_co, co); + } + space_transform_apply(&calc->local2target, tmp_co); //Use local proximity heuristics (to reduce the nearest search) // @@ -348,172 +394,115 @@ void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc) int i; //Options about projection direction - const char use_normal = calc->smd->shrinkOpts; - float proj_axis[3] = {0.0f, 0.0f, 0.0f}; - MVert *vert = NULL; //Needed in case of vertex normal - DerivedMesh* ss_mesh = NULL; + const char use_normal = calc->smd->shrinkOpts; + float proj_axis[3] = {0.0f, 0.0f, 0.0f}; //Raycast and tree stuff BVHTreeRayHit hit; - BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh; //target + BVHTreeFromMesh treeData= NULL_BVHTreeFromMesh; //auxiliar target - DerivedMesh * aux_mesh = NULL; - BVHTreeFromMesh auxData= NULL_BVHTreeFromMesh; + DerivedMesh *auxMesh = NULL; + BVHTreeFromMesh auxData = NULL_BVHTreeFromMesh; SpaceTransform local2aux; -do -{ + //If the user doesn't allows to project in any direction of projection axis + //then theres nothing todo. + if((use_normal & (MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR | MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR)) == 0) + return; + //Prepare data to retrieve the direction in which we should project each vertex if(calc->smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL) { - //No Mvert information: jump to "free memory and return" part - if(calc->original == NULL) break; - - if(calc->smd->subsurfLevels) - { - SubsurfModifierData smd; - memset(&smd, 0, sizeof(smd)); - smd.subdivType = ME_CC_SUBSURF; //catmull clark - smd.levels = calc->smd->subsurfLevels; //levels - - ss_mesh = subsurf_make_derived_from_derived(calc->original, &smd, FALSE, NULL, 0, 0); - - if(ss_mesh) - { - vert = ss_mesh->getVertDataArray(ss_mesh, CD_MVERT); - if(vert) - { - //TRICKY: this code assumes subsurface will have the transformed original vertices - //in their original order at the end of the vert array. - vert = vert - + ss_mesh->getNumVerts(ss_mesh) - - calc->original->getNumVerts(calc->original); - } - } - - //To make sure we are not letting any memory behind - assert(smd.emCache == NULL); - assert(smd.mCache == NULL); - } - else - vert = calc->original->getVertDataArray(calc->original, CD_MVERT); - - //Not able to get vert information: jump to "free memory and return" part - if(vert == NULL) break; + if(calc->vert == NULL) return; } else { - //The code supports any axis that is a combination of X,Y,Z.. altought currently UI only allows to set the 3 diferent axis + //The code supports any axis that is a combination of X,Y,Z + //altought currently UI only allows to set the 3 diferent axis if(calc->smd->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_X_AXIS) proj_axis[0] = 1.0f; if(calc->smd->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_Y_AXIS) proj_axis[1] = 1.0f; if(calc->smd->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_Z_AXIS) proj_axis[2] = 1.0f; Normalize(proj_axis); - //Invalid projection direction: jump to "free memory and return" part - if(INPR(proj_axis, proj_axis) < FLT_EPSILON) break; + //Invalid projection direction + if(INPR(proj_axis, proj_axis) < FLT_EPSILON) + return; } - //If the user doesn't allows to project in any direction of projection axis... then theres nothing todo. - if((use_normal & (MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR | MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR)) == 0) - break; //jump to "free memory and return" part - - - //Build target tree - BENCH(bvhtree_from_mesh_faces(&treeData, calc->target, calc->keepDist, 4, 6)); - if(treeData.tree == NULL) - break; //jump to "free memory and return" part - - - //Build auxiliar target if(calc->smd->auxTarget) { + auxMesh = object_get_derived_final(calc->smd->auxTarget, CD_MASK_BAREMESH); space_transform_setup( &local2aux, calc->ob, calc->smd->auxTarget); - - aux_mesh = CDDM_copy( object_get_derived_final(calc->smd->auxTarget, CD_MASK_BAREMESH) ); //TODO currently we need a copy in case object_get_derived_final returns an emDM that does not defines getVertArray or getFace array - if(aux_mesh) - BENCH(bvhtree_from_mesh_faces(&auxData, aux_mesh, 0.0, 4, 6)); - else - printf("Auxiliar target finalDerived mesh is null\n"); } - - //Now, everything is ready to project the vertexs! -#pragma omp parallel for private(i,hit) schedule(static) - for(i = 0; i<calc->numVerts; ++i) + //After sucessufuly build the trees, start projection vertexs + if( bvhtree_from_mesh_faces(&treeData, calc->target, calc->keepDist, 4, 6) + && (auxMesh == NULL || bvhtree_from_mesh_faces(&auxData, auxMesh, 0.0, 4, 6))) { - float *co = calc->vertexCos[i]; - float tmp_co[3], tmp_no[3]; - float lim = 10000.0f; //TODO: we should use FLT_MAX here, but sweepsphere code isnt prepared for that - float weight = vertexgroup_get_vertex_weight(calc->dvert, i, calc->vgroup); - - if(weight == 0.0f) continue; - if(ss_mesh) - { - VECCOPY(tmp_co, vert[i].co); - } - else +#pragma omp parallel for private(i,hit) schedule(static) + for(i = 0; i<calc->numVerts; ++i) { - VECCOPY(tmp_co, co); - } + float *co = calc->vertexCos[i]; + float tmp_co[3], tmp_no[3]; + float weight = vertexgroup_get_vertex_weight(calc->dvert, i, calc->vgroup); + if(weight == 0.0f) continue; - if(vert) - NormalShortToFloat(tmp_no, vert[i].no); - else - VECCOPY( tmp_no, proj_axis ); - + if(calc->vert) + { + VECCOPY(tmp_co, calc->vert[i].co); + if(calc->smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL) + NormalShortToFloat(tmp_no, calc->vert[i].no); + else + VECCOPY(tmp_no, proj_axis); + } + else + { + VECCOPY(tmp_co, co); + VECCOPY(tmp_no, proj_axis); + } - hit.index = -1; - hit.dist = lim; + hit.index = -1; + hit.dist = 10000.0f; //TODO: we should use FLT_MAX here, but sweepsphere code isnt prepared for that - //Project over positive direction of axis - if(use_normal & MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR) - { + //Project over positive direction of axis + if(use_normal & MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR) + { - if(auxData.tree) - normal_projection_project_vertex(0, tmp_co, tmp_no, &local2aux, auxData.tree, &hit, auxData.raycast_callback, &auxData); + if(auxData.tree) + normal_projection_project_vertex(0, tmp_co, tmp_no, &local2aux, auxData.tree, &hit, auxData.raycast_callback, &auxData); - normal_projection_project_vertex(calc->smd->shrinkOpts, tmp_co, tmp_no, &calc->local2target, treeData.tree, &hit, treeData.raycast_callback, &treeData); - } + normal_projection_project_vertex(calc->smd->shrinkOpts, tmp_co, tmp_no, &calc->local2target, treeData.tree, &hit, treeData.raycast_callback, &treeData); + } - //Project over negative direction of axis - if(use_normal & MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR) - { - float inv_no[3] = { -tmp_no[0], -tmp_no[1], -tmp_no[2] }; + //Project over negative direction of axis + if(use_normal & MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR) + { + float inv_no[3] = { -tmp_no[0], -tmp_no[1], -tmp_no[2] }; - if(auxData.tree) - normal_projection_project_vertex(0, tmp_co, inv_no, &local2aux, auxData.tree, &hit, auxData.raycast_callback, &auxData); + if(auxData.tree) + normal_projection_project_vertex(0, tmp_co, inv_no, &local2aux, auxData.tree, &hit, auxData.raycast_callback, &auxData); - normal_projection_project_vertex(calc->smd->shrinkOpts, tmp_co, inv_no, &calc->local2target, treeData.tree, &hit, treeData.raycast_callback, &treeData); - } + normal_projection_project_vertex(calc->smd->shrinkOpts, tmp_co, inv_no, &calc->local2target, treeData.tree, &hit, treeData.raycast_callback, &treeData); + } - if(hit.index != -1) - { - VecLerpf(co, co, hit.co, weight); + if(hit.index != -1) + { + VecLerpf(co, co, hit.co, weight); + } } } - -//Simple do{} while(0) structure to allow to easily jump to the "free memory and return" part -} while(0); - //free data structures - free_bvhtree_from_mesh(&treeData); free_bvhtree_from_mesh(&auxData); - - if(aux_mesh) - aux_mesh->release(aux_mesh); - - if(ss_mesh) - ss_mesh->release(ss_mesh); } /* @@ -529,8 +518,6 @@ void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc) BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh; BVHTreeNearest nearest = NULL_BVHTreeNearest; - - //Create a bvh-tree of the given target BENCH(bvhtree_from_mesh_faces( &treeData, calc->target, 0.0, 2, 6)); if(treeData.tree == NULL) @@ -554,7 +541,14 @@ void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc) if(weight == 0.0f) continue; //Convert the vertex to tree coordinates - VECCOPY(tmp_co, co); + if(calc->vert) + { + VECCOPY(tmp_co, calc->vert[i].co); + } + else + { + VECCOPY(tmp_co, co); + } space_transform_apply(&calc->local2target, tmp_co); //Use local proximity heuristics (to reduce the nearest search) @@ -593,7 +587,6 @@ void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc) } } - free_bvhtree_from_mesh(&treeData); } diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index c3a355160e0..c88e06a9993 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -1850,6 +1850,13 @@ static void lib_link_constraints(FileData *fd, ID *id, ListBase *conlist) data->tar = newlibadr(fd, id->lib, data->tar); } break; + case CONSTRAINT_TYPE_SHRINKWRAP: + { + bShrinkwrapConstraint *data; + data= ((bShrinkwrapConstraint*)con->data); + data->target = newlibadr(fd, id->lib, data->target); + } + break; case CONSTRAINT_TYPE_NULL: break; } @@ -8633,6 +8640,12 @@ static void expand_constraints(FileData *fd, Main *mainvar, ListBase *lb) expand_doit(fd, mainvar, data->tar); } break; + case CONSTRAINT_TYPE_SHRINKWRAP: + { + bShrinkwrapConstraint *data = (bShrinkwrapConstraint*)curcon->data; + expand_doit(fd, mainvar, data->target); + } + break; default: break; } diff --git a/source/blender/include/butspace.h b/source/blender/include/butspace.h index 868d0c3e6c0..8a9c1933c97 100644 --- a/source/blender/include/butspace.h +++ b/source/blender/include/butspace.h @@ -729,6 +729,7 @@ enum { B_CONSTRAINT_ADD_PYTHON, B_CONSTRAINT_ADD_CLAMPTO, B_CONSTRAINT_ADD_TRANSFORM, + B_CONSTRAINT_ADD_SHRINKWRAP, B_CONSTRAINT_INF }; diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h index fe19cf60f12..79f032d0d21 100644 --- a/source/blender/makesdna/DNA_constraint_types.h +++ b/source/blender/makesdna/DNA_constraint_types.h @@ -317,6 +317,15 @@ typedef struct bDistLimitConstraint { int pad; } bDistLimitConstraint; +typedef struct bShrinkwrapConstraint { + Object *target; + float dist; /* distance to kept from target */ + short shrinkType; /* shrink type (look on MOD shrinkwrap for values) */ + char projAxis; /* axis to project over UP_X, UP_Y, UP_Z */ + char pad[9]; +} bShrinkwrapConstraint; + + /* ------------------------------------------ */ /* bConstraint->type @@ -344,10 +353,11 @@ typedef enum B_CONSTAINT_TYPES { CONSTRAINT_TYPE_RIGIDBODYJOINT, /* rigidbody constraint */ CONSTRAINT_TYPE_CLAMPTO, /* clampto constraint */ CONSTRAINT_TYPE_TRANSFORM, /* transformation (loc/rot/size -> loc/rot/size) constraint */ + CONSTRAINT_TYPE_SHRINKWRAP, /* shrinkwrap (loc/rot) constraint */ /* NOTE: everytime a new constraint is added, update this */ - NUM_CONSTRAINT_TYPES= CONSTRAINT_TYPE_TRANSFORM + NUM_CONSTRAINT_TYPES= CONSTRAINT_TYPE_SHRINKWRAP } B_CONSTRAINT_TYPES; /* bConstraint->flag */ diff --git a/source/blender/src/buttons_editing.c b/source/blender/src/buttons_editing.c index 779909ec713..1ecc63fe93d 100644 --- a/source/blender/src/buttons_editing.c +++ b/source/blender/src/buttons_editing.c @@ -1735,6 +1735,7 @@ static int modifier_is_fluid_particles(ModifierData *md) { } return 0; } + static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco, int *yco, int index, int cageIndex, int lastCageIndex) { ModifierTypeInfo *mti = modifierType_getInfo(md->type); @@ -1903,12 +1904,10 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco height = 94; } else if (md->type==eModifierType_Shrinkwrap) { ShrinkwrapModifierData *smd = (ShrinkwrapModifierData*) md; - height = 86 + 3; + height = 105 + 3; + if (smd->shrinkType == MOD_SHRINKWRAP_PROJECT) - { height += 19*5; - if(smd->projAxis == 0) height += 19; - } else if (smd->shrinkType == MOD_SHRINKWRAP_NEAREST_SURFACE) height += 19; } else if (md->type == eModifierType_Mask) { @@ -2596,16 +2595,14 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco cy -= 3; uiDefButS(block, MENU, B_MODIFIER_RECALC, shrinktypemenu, lx,(cy-=19),buttonWidth,19, &smd->shrinkType, 0, 0, 0, 0, "Selects type of shrinkwrap algorithm for target position."); + uiDefButC(block, NUM, B_MODIFIER_RECALC, "SS Levels:", lx, (cy-=19), buttonWidth,19, &smd->subsurfLevels, 0, 6, 0, 0, "This indicates the number of CCSubdivisions that must be performed before extracting vertexs positions and normals"); + if (smd->shrinkType == MOD_SHRINKWRAP_PROJECT){ /* UI for projection axis */ uiBlockBeginAlign(block); uiDefButC(block, ROW, B_MODIFIER_RECALC, "Normal" , lx,(cy-=19),buttonWidth,19, &smd->projAxis, 18.0, MOD_SHRINKWRAP_PROJECT_OVER_NORMAL, 0, 0, "Projection over X axis"); - if(smd->projAxis == 0) - { - uiDefButC(block, NUM, B_MODIFIER_RECALC, "SS Levels:", lx, (cy-=19), buttonWidth,19, &smd->subsurfLevels, 0, 6, 0, 0, "This indicates the number of CCSubdivisions that must be performed before extracting vertexs positions and normals"); - } uiDefButBitC(block, TOG, MOD_SHRINKWRAP_PROJECT_OVER_X_AXIS, B_MODIFIER_RECALC, "X", lx+buttonWidth/3*0,(cy-=19),buttonWidth/3,19, &smd->projAxis, 0, 0, 0, 0, "Projection over X axis"); uiDefButBitC(block, TOG, MOD_SHRINKWRAP_PROJECT_OVER_Y_AXIS, B_MODIFIER_RECALC, "Y", lx+buttonWidth/3*1,cy,buttonWidth/3,19, &smd->projAxis, 0, 0, 0, 0, "Projection over Y axis"); @@ -6971,3 +6968,4 @@ void editing_panels() } uiClearButLock(); } + diff --git a/source/blender/src/buttons_object.c b/source/blender/src/buttons_object.c index 7161bc8c266..a41f954c4d8 100644 --- a/source/blender/src/buttons_object.c +++ b/source/blender/src/buttons_object.c @@ -1752,6 +1752,37 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-10, *yco-height, width+40,height-1, NULL, 5.0, 0.0, 12, rb_col, ""); } break; + + case CONSTRAINT_TYPE_SHRINKWRAP: + { + bShrinkwrapConstraint *data = con->data; + + height = 78; + if(data->shrinkType == MOD_SHRINKWRAP_PROJECT) + height += 18; + + uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-10, *yco-height, width+40,height-1, NULL, 5.0, 0.0, 12, rb_col, ""); + + /* Draw parameters */ + uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Target:", *xco+65, *yco-24, 90, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); + uiDefIDPoinBut(block, test_meshobpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+120, *yco-24, 135, 18, &data->target, "Target Object"); + + uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Dist:", *xco + 75, *yco-42, 90, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+120, *yco-42, 135, 18, &data->dist, -100.0f, 100.0f, 1.0f, 0.0f, "Distance to target"); + + uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Type:", *xco + 70, *yco-60, 90, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); + uiDefButS(block, MENU, B_MODIFIER_RECALC, "Shrinkwrap Type%t|Nearest Surface Point %x0|Projection %x1|Nearest Vertex %x2", *xco+120, *yco-60, 135, 18, &data->shrinkType, 0, 0, 0, 0, "Selects type of shrinkwrap algorithm for target position."); + + if(data->shrinkType == MOD_SHRINKWRAP_PROJECT) + { + /* Draw XYZ toggles */ + uiDefBut(block, LABEL,B_CONSTRAINT_TEST, "Axis:", *xco+ 75, *yco-78, 90, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); + uiDefButBitC(block, TOG, MOD_SHRINKWRAP_PROJECT_OVER_X_AXIS, B_CONSTRAINT_TEST, "X",*xco+120, *yco-78, 45, 18, &data->projAxis, 0, 0, 0, 0, "Projection over X axis"); + uiDefButBitC(block, TOG, MOD_SHRINKWRAP_PROJECT_OVER_Y_AXIS, B_CONSTRAINT_TEST, "Y",*xco+165, *yco-78, 45, 18, &data->projAxis, 0, 0, 0, 0, "Projection over Y axis"); + uiDefButBitC(block, TOG, MOD_SHRINKWRAP_PROJECT_OVER_Z_AXIS, B_CONSTRAINT_TEST, "Z",*xco+210, *yco-78, 45, 18, &data->projAxis, 0, 0, 0, 0, "Projection over Z axis"); + } + } + break; default: height = 0; break; @@ -1813,6 +1844,7 @@ static uiBlock *add_constraintmenu(void *arg_unused) uiDefBut(block, BUTM, B_CONSTRAINT_ADD_MINMAX, "Floor", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, ""); uiDefBut(block, BUTM, B_CONSTRAINT_ADD_LOCKTRACK, "Locked Track", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, ""); uiDefBut(block, BUTM, B_CONSTRAINT_ADD_FOLLOWPATH, "Follow Path", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, ""); + uiDefBut(block, BUTM, B_CONSTRAINT_ADD_SHRINKWRAP, "Shrinkwrap" , 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, ""); uiDefBut(block, SEPR, 0, "", 0, yco-=6, 120, 6, NULL, 0.0, 0.0, 0, 0, ""); @@ -2049,6 +2081,14 @@ void do_constraintbuts(unsigned short event) BIF_undo_push("Add constraint"); } break; + case B_CONSTRAINT_ADD_SHRINKWRAP: + { + con = add_new_constraint(CONSTRAINT_TYPE_SHRINKWRAP); + add_constraint_to_active(ob, con); + + BIF_undo_push("Add constraint"); + } + break; default: break; diff --git a/source/blender/src/editconstraint.c b/source/blender/src/editconstraint.c index 42972e4aa5d..865bf1ba29d 100644 --- a/source/blender/src/editconstraint.c +++ b/source/blender/src/editconstraint.c @@ -366,6 +366,8 @@ void add_constraint (short only_IK) nr= pupmenu("Add Constraint to Active Bone%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Limit Distance%x21|%l|Track To%x3|Floor%x4|Locked Track%x5|Stretch To%x7|%l|Action%x16|Script%x18"); else if ((obsel) && (obsel->type==OB_CURVE)) nr= pupmenu("Add Constraint to Active Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Limit Distance%x21|%l|Track To%x3|Floor%x4|Locked Track%x5|Follow Path%x6|Clamp To%x17|Stretch To%x7|%l|Action%x16|Script%x18"); + else if ((obsel) && (obsel->type==OB_MESH)) + nr= pupmenu("Add Constraint to Active Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Limit Distance%x21|%l|Track To%x3|Floor%x4|Locked Track%x5|Shrinkwrap%x22|Stretch To%x7|%l|Action%x16|Script%x18"); else if (obsel) nr= pupmenu("Add Constraint to Active Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Limit Distance%x21|%l|Track To%x3|Floor%x4|Locked Track%x5|Stretch To%x7|%l|Action%x16|Script%x18"); else @@ -374,6 +376,8 @@ void add_constraint (short only_IK) else { if ((obsel) && (obsel->type==OB_CURVE)) nr= pupmenu("Add Constraint to Active Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Limit Distance%x21|%l|Track To%x3|Floor%x4|Locked Track%x5|Follow Path%x6|Clamp To%x17|%l|Action%x16|Script%x18"); + else if ((obsel) && (obsel->type==OB_MESH)) + nr= pupmenu("Add Constraint to Active Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Limit Distance%x21|%l|Track To%x3|Floor%x4|Locked Track%x5|Shrinkwrap%x22|%l|Action%x16|Script%x18"); else if (obsel) nr= pupmenu("Add Constraint to Active Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Limit Distance%x21|%l|Track To%x3|Floor%x4|Locked Track%x5|%l|Action%x16|Script%x18"); else @@ -476,6 +480,7 @@ void add_constraint (short only_IK) } else if (nr==20) con = add_new_constraint(CONSTRAINT_TYPE_TRANSFORM); else if (nr==21) con = add_new_constraint(CONSTRAINT_TYPE_DISTLIMIT); + else if (nr==22) con = add_new_constraint(CONSTRAINT_TYPE_SHRINKWRAP); if (con==NULL) return; /* paranoia */ |