Merging Shrinkwrap Constraint!
authorAndre Susano Pinto <andresusanopinto@gmail.com>
Wed, 15 Apr 2009 19:33:25 +0000 (19:33 +0000)
committerAndre Susano Pinto <andresusanopinto@gmail.com>
Wed, 15 Apr 2009 19:33:25 +0000 (19:33 +0000)
+bvhtree cache (if the derived model doenst gets destroyed then the same BVHtree can be used)
this was needed to allow shrinkwrap constraint to be usable.

It has been ready for a long time.. but only got merged now, for 2.49.

13 files changed:
source/blender/blenkernel/BKE_DerivedMesh.h
source/blender/blenkernel/BKE_bvhutils.h
source/blender/blenkernel/BKE_shrinkwrap.h
source/blender/blenkernel/intern/DerivedMesh.c
source/blender/blenkernel/intern/bvhutils.c
source/blender/blenkernel/intern/constraint.c
source/blender/blenkernel/intern/shrinkwrap.c
source/blender/blenloader/intern/readfile.c
source/blender/include/butspace.h
source/blender/makesdna/DNA_constraint_types.h
source/blender/src/buttons_editing.c
source/blender/src/buttons_object.c
source/blender/src/editconstraint.c

index 5a1e266..263b171 100644 (file)
@@ -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 */
 
index dd9ea61..66c8d99 100644 (file)
@@ -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
 
index eed22ff..6ce449f 100644 (file)
@@ -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;
 
index c934f7d..d43cbde 100644 (file)
@@ -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);
index ae44984..d9e0058 100644 (file)
@@ -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;
+}
+
+
index db98c20..f93fc40 100644 (file)
@@ -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
index ab98fb1..6784f01 100644 (file)
@@ -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);
 }
 
index c3a3551..c88e06a 100644 (file)
@@ -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;
                }
index 868d0c3..8a9c193 100644 (file)
@@ -729,6 +729,7 @@ enum {
        B_CONSTRAINT_ADD_PYTHON,
        B_CONSTRAINT_ADD_CLAMPTO,
        B_CONSTRAINT_ADD_TRANSFORM,
+       B_CONSTRAINT_ADD_SHRINKWRAP,
        B_CONSTRAINT_INF
 };
 
index fe19cf6..79f032d 100644 (file)
@@ -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 */
index 779909e..1ecc63f 100644 (file)
@@ -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();
 }
+
index 7161bc8..a41f954 100644 (file)
@@ -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;
index 42972e4..865bf1b 100644 (file)
@@ -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 */