Merged shrinkwrap modifier from soc-2008-jaguarandi
authorAndre Susano Pinto <andresusanopinto@gmail.com>
Fri, 22 Aug 2008 00:35:14 +0000 (00:35 +0000)
committerAndre Susano Pinto <andresusanopinto@gmail.com>
Fri, 22 Aug 2008 00:35:14 +0000 (00:35 +0000)
1  2 
source/blender/blenkernel/intern/modifier.c
source/blender/blenkernel/intern/shrinkwrap.c
source/blender/makesdna/DNA_modifier_types.h
source/blender/src/buttons_editing.c

index 777be445e63928a87cf90e12e31937df75b3a960,f33f33d9d46d8a407e3fcb9b6aa4f43cf21c4cd8..4c74fe1cca2c8f551cc218669bbc7793f4456de3
  #include "BKE_utildefines.h"
  #include "depsgraph_private.h"
  #include "BKE_bmesh.h"
 -#include "BKE_simple_deform.h"
+ #include "BKE_deform.h"
+ #include "BKE_shrinkwrap.h"
  
  #include "LOD_DependKludge.h"
  #include "LOD_decimation.h"
@@@ -7236,6 -7223,189 +7222,126 @@@ static void meshdeformModifier_deformVe
                dm->release(dm);
  }
  
 -/* SimpleDeform */
 -static void simpledeformModifier_initData(ModifierData *md)
 -{
 -      SimpleDeformModifierData *smd = (SimpleDeformModifierData*) md;
 -
 -      smd->mode = MOD_SIMPLEDEFORM_MODE_TWIST;
 -      smd->axis         =  0;
 -
 -      smd->origin   =  NULL;
 -      smd->factor   =  0.35;
 -      smd->limit[0] = -1000.0f;
 -      smd->limit[1] =  1000.0f;
 -}
 -
 -static void simpledeformModifier_copyData(ModifierData *md, ModifierData *target)
 -{
 -      SimpleDeformModifierData *smd  = (SimpleDeformModifierData*)md;
 -      SimpleDeformModifierData *tsmd = (SimpleDeformModifierData*)target;
 -
 -      tsmd->mode      = smd->mode;
 -      tsmd->axis  = smd->axis;
 -      tsmd->origin= smd->origin;
 -      tsmd->factor= smd->factor;
 -      memcpy(tsmd->limit, smd->limit, sizeof(tsmd->limit));
 -}
 -
 -static void simpledeformModifier_deformVerts(ModifierData *md, Object *ob, DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
 -{
 -      SimpleDeformModifier_do((SimpleDeformModifierData*)md, ob, derivedData, vertexCos, numVerts);
 -}
 -
 -static void simpledeformModifier_deformVertsEM(ModifierData *md, Object *ob, EditMesh *editData, DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
 -{
 -      SimpleDeformModifier_do((SimpleDeformModifierData*)md, ob, derivedData, vertexCos, numVerts);
 -}
 -
 -static CustomDataMask simpledeformModifier_requiredDataMask(ModifierData *md)
 -{
 -      SimpleDeformModifierData *smd = (SimpleDeformModifierData *)md;
 -      CustomDataMask dataMask = 0;
 -
 -      /* ask for vertexgroups if we need them */
 -      if(smd->vgroup_name[0])
 -              dataMask |= (1 << CD_MDEFORMVERT);
 -
 -      return dataMask;
 -}
 -
 -static void simpledeformModifier_foreachObjectLink(ModifierData *md, Object *ob, void (*walk)(void *userData, Object *ob, Object **obpoin), void *userData)
 -{
 -      SimpleDeformModifierData *smd  = (SimpleDeformModifierData*)md;
 -      walk(userData, ob, &smd->origin);
 -}
 -
 -static void simpledeformModifier_updateDepgraph(ModifierData *md, DagForest *forest, Object *ob, DagNode *obNode)
 -{
 -      SimpleDeformModifierData *smd  = (SimpleDeformModifierData*)md;
 -
 -      if (smd->origin)
 -              dag_add_relation(forest, dag_get_node(forest, smd->origin), obNode, DAG_RL_OB_DATA, "SimpleDeform Modifier");
 -}
 -
 -
+ /* Shrinkwrap */
+ static void shrinkwrapModifier_initData(ModifierData *md)
+ {
+       ShrinkwrapModifierData *smd = (ShrinkwrapModifierData*) md;
+       smd->shrinkType = MOD_SHRINKWRAP_NEAREST_SURFACE;
+       smd->shrinkOpts = MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR;
+       smd->keepDist   = 0.0f;
+       smd->target             = NULL;
+       smd->auxTarget  = NULL;
+ }
+ static void shrinkwrapModifier_copyData(ModifierData *md, ModifierData *target)
+ {
+       ShrinkwrapModifierData *smd  = (ShrinkwrapModifierData*)md;
+       ShrinkwrapModifierData *tsmd = (ShrinkwrapModifierData*)target;
+       tsmd->target    = smd->target;
+       tsmd->auxTarget = smd->auxTarget;
+       strcpy(tsmd->vgroup_name, smd->vgroup_name);
+       tsmd->keepDist  = smd->keepDist;
+       tsmd->shrinkType= smd->shrinkType;
+       tsmd->shrinkOpts= smd->shrinkOpts;
+ }
+ CustomDataMask shrinkwrapModifier_requiredDataMask(ModifierData *md)
+ {
+       ShrinkwrapModifierData *smd = (ShrinkwrapModifierData *)md;
+       CustomDataMask dataMask = 0;
+       /* ask for vertexgroups if we need them */
+       if(smd->vgroup_name[0])
+               dataMask |= (1 << CD_MDEFORMVERT);
+       if(smd->shrinkType == MOD_SHRINKWRAP_PROJECT
+       && smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL)
+               dataMask |= (1 << CD_MVERT);
+               
+       return dataMask;
+ }
+ static int shrinkwrapModifier_isDisabled(ModifierData *md)
+ {
+       ShrinkwrapModifierData *smd = (ShrinkwrapModifierData*) md;
+       return !smd->target;
+ }
+ static void shrinkwrapModifier_foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData)
+ {
+       ShrinkwrapModifierData *smd = (ShrinkwrapModifierData*) md;
+       walk(userData, ob, &smd->target);
+       walk(userData, ob, &smd->auxTarget);
+ }
+ static void shrinkwrapModifier_deformVerts(ModifierData *md, Object *ob, DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
+ {
+       DerivedMesh *dm = NULL;
+       CustomDataMask dataMask = shrinkwrapModifier_requiredDataMask(md);
+       /* We implement requiredDataMask but thats not really usefull since mesh_calc_modifiers pass a NULL derivedData or without the modified vertexs applied */
+       if(shrinkwrapModifier_requiredDataMask(md))
+       {
+               if(derivedData) dm = CDDM_copy(derivedData);
+               else if(ob->type==OB_MESH) dm = CDDM_from_mesh(ob->data, ob);
+               else return;
+               if(dataMask & CD_MVERT)
+               {
+                       CDDM_apply_vert_coords(dm, vertexCos);
+                       CDDM_calc_normals(dm);
+               }
+       }
+       shrinkwrapModifier_deform((ShrinkwrapModifierData*)md, ob, dm, vertexCos, numVerts);
+       if(dm)
+               dm->release(dm);
+ }
+ static void shrinkwrapModifier_deformVertsEM(ModifierData *md, Object *ob, EditMesh *editData, DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
+ {
+       DerivedMesh *dm = NULL;
+       CustomDataMask dataMask = shrinkwrapModifier_requiredDataMask(md);
+       if(dataMask)
+       {
+               if(derivedData) dm = CDDM_copy(derivedData);
+               else if(ob->type==OB_MESH) dm = CDDM_from_editmesh(editData, ob->data);
+               else return;
+               if(dataMask & CD_MVERT)
+               {
+                       CDDM_apply_vert_coords(dm, vertexCos);
+                       CDDM_calc_normals(dm);
+               }
+       }
+       shrinkwrapModifier_deform((ShrinkwrapModifierData*)md, ob, dm, vertexCos, numVerts);
+       if(dm)
+               dm->release(dm);
+ }
+ static void shrinkwrapModifier_updateDepgraph(ModifierData *md, DagForest *forest, Object *ob, DagNode *obNode)
+ {
+       ShrinkwrapModifierData *smd = (ShrinkwrapModifierData*) md;
+       if (smd->target)
+               dag_add_relation(forest, dag_get_node(forest, smd->target),   obNode, DAG_RL_OB_DATA | DAG_RL_DATA_DATA, "Shrinkwrap Modifier");
+       if (smd->auxTarget)
+               dag_add_relation(forest, dag_get_node(forest, smd->auxTarget), obNode, DAG_RL_OB_DATA | DAG_RL_DATA_DATA, "Shrinkwrap Modifier");
+ }
  /***/
  
  static ModifierTypeInfo typeArr[NUM_MODIFIER_TYPES];
@@@ -7557,6 -7727,37 +7663,21 @@@ ModifierTypeInfo *modifierType_getInfo(
                mti->requiredDataMask = explodeModifier_requiredDataMask;
                mti->applyModifier = explodeModifier_applyModifier;
  
 -
+               mti = INIT_TYPE(Shrinkwrap);
+               mti->type = eModifierTypeType_OnlyDeform;
+               mti->flags = eModifierTypeFlag_AcceptsMesh
+                               | eModifierTypeFlag_AcceptsCVs
+                               | eModifierTypeFlag_SupportsEditmode
+                               | eModifierTypeFlag_EnableInEditmode;
 -              mti = INIT_TYPE(SimpleDeform);
 -              mti->type = eModifierTypeType_OnlyDeform;
 -              mti->flags = eModifierTypeFlag_AcceptsMesh
 -                              | eModifierTypeFlag_AcceptsCVs                          
 -                              | eModifierTypeFlag_SupportsEditmode
 -                              | eModifierTypeFlag_EnableInEditmode;
 -              mti->initData = simpledeformModifier_initData;
 -              mti->copyData = simpledeformModifier_copyData;
 -              mti->requiredDataMask = simpledeformModifier_requiredDataMask;
 -              mti->deformVerts = simpledeformModifier_deformVerts;
 -              mti->deformVertsEM = simpledeformModifier_deformVertsEM;
 -              mti->foreachObjectLink = simpledeformModifier_foreachObjectLink;
 -              mti->updateDepgraph = simpledeformModifier_updateDepgraph;
 -
 -
+               mti->initData = shrinkwrapModifier_initData;
+               mti->copyData = shrinkwrapModifier_copyData;
+               mti->requiredDataMask = shrinkwrapModifier_requiredDataMask;
+               mti->isDisabled = shrinkwrapModifier_isDisabled;
+               mti->foreachObjectLink = shrinkwrapModifier_foreachObjectLink;
+               mti->deformVerts = shrinkwrapModifier_deformVerts;
+               mti->deformVertsEM = shrinkwrapModifier_deformVertsEM;
+               mti->updateDepgraph = shrinkwrapModifier_updateDepgraph;
                typeArrInit = 0;
  #undef INIT_TYPE
        }
index 0000000000000000000000000000000000000000,5c020bf23392b01d5fa78ddbbd051b8cc52f92d7..292a800e9cd677b843b53bf4576353135740923a
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,599 +1,588 @@@
 -#ifndef _WIN32
+ /**
+  * shrinkwrap.c
+  *
+  * ***** BEGIN GPL LICENSE BLOCK *****
+  *
+  * This program is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU General Public License
+  * as published by the Free Software Foundation; either version 2
+  * of the License, or (at your option) any later version.
+  *
+  * This program is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  *
+  * You should have received a copy of the GNU General Public License
+  * along with this program; if not, write to the Free Software Foundation,
+  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+  *
+  * The Original Code is Copyright (C) Blender Foundation.
+  * All rights reserved.
+  *
+  * The Original Code is: all of this file.
+  *
+  * Contributor(s): AndrĂ© Pinto
+  *
+  * ***** END GPL LICENSE BLOCK *****
+  */
+ #include <string.h>
+ #include <float.h>
+ #include <math.h>
+ #include <memory.h>
+ #include <stdio.h>
+ #include <time.h>
+ #include <assert.h>
+ #include "DNA_object_types.h"
+ #include "DNA_modifier_types.h"
+ #include "DNA_meshdata_types.h"
+ #include "DNA_mesh_types.h"
+ #include "BKE_shrinkwrap.h"
+ #include "BKE_DerivedMesh.h"
+ #include "BKE_utildefines.h"
+ #include "BKE_deform.h"
+ #include "BKE_cdderivedmesh.h"
+ #include "BKE_displist.h"
+ #include "BKE_global.h"
+ #include "BKE_subsurf.h"
+ #include "BLI_arithb.h"
+ #include "BLI_kdtree.h"
+ #include "BLI_kdopbvh.h"
+ #include "RE_raytrace.h"
+ #include "MEM_guardedalloc.h"
+ /* Util macros */
+ #define TO_STR(a)     #a
+ #define JOIN(a,b)     a##b
+ #define OUT_OF_MEMORY()       ((void)printf("Shrinkwrap: Out of memory\n"))
+ /* Benchmark macros */
 -              if(!calc.target)
 -              {
 -                      printf("Target derived mesh is null! :S\n");
 -              }
 -
++#if !defined(_WIN32) && 0
+ #include <sys/time.h>
+ #define BENCH(a)      \
+       do {                    \
+               double _t1, _t2;                                \
+               struct timeval _tstart, _tend;  \
+               clock_t _clock_init = clock();  \
+               gettimeofday ( &_tstart, NULL); \
+               (a);                                                    \
+               gettimeofday ( &_tend, NULL);   \
+               _t1 = ( double ) _tstart.tv_sec + ( double ) _tstart.tv_usec/ ( 1000*1000 );    \
+               _t2 = ( double )   _tend.tv_sec + ( double )   _tend.tv_usec/ ( 1000*1000 );    \
+               printf("%s: %fs (real) %fs (cpu)\n", #a, _t2-_t1, (float)(clock()-_clock_init)/CLOCKS_PER_SEC);\
+       } while(0)
+ #else
+ #define BENCH(a)      (a)
+ #endif
+ typedef void ( *Shrinkwrap_ForeachVertexCallback) (DerivedMesh *target, float *co, float *normal);
+ /* get derived mesh */
+ //TODO is anyfunction that does this? returning the derivedFinal witouth we caring if its in edit mode or not?
+ DerivedMesh *object_get_derived_final(Object *ob, CustomDataMask dataMask)
+ {
+       if (ob==G.obedit)
+       {
+               DerivedMesh *final = NULL;
+               editmesh_get_derived_cage_and_final(&final, dataMask);
+               return final;
+       }
+       else
+               return mesh_get_derived_final(ob, dataMask);
+ }
+ /* Space transform */
+ void space_transform_from_matrixs(SpaceTransform *data, float local[4][4], float target[4][4])
+ {
+       float itarget[4][4];
+       Mat4Invert(itarget, target);
+       Mat4MulSerie(data->local2target, itarget, local, 0, 0, 0, 0, 0, 0);
+       Mat4Invert(data->target2local, data->local2target);
+ }
+ void space_transform_apply(const SpaceTransform *data, float *co)
+ {
+       VecMat4MulVecfl(co, data->local2target, co);
+ }
+ void space_transform_invert(const SpaceTransform *data, float *co)
+ {
+       VecMat4MulVecfl(co, data->target2local, co);
+ }
+ void space_transform_apply_normal(const SpaceTransform *data, float *no)
+ {
+       Mat4Mul3Vecfl(data->local2target, no);
+       Normalize(no); // TODO: could we just determine de scale value from the matrix?
+ }
+ void space_transform_invert_normal(const SpaceTransform *data, float *no)
+ {
+       Mat4Mul3Vecfl(data->target2local, no);
+       Normalize(no); // TODO: could we just determine de scale value from the matrix?
+ }
+ /*
+  * Returns the squared distance between two given points
+  */
+ static float squared_dist(const float *a, const float *b)
+ {
+       float tmp[3];
+       VECSUB(tmp, a, b);
+       return INPR(tmp, tmp);
+ }
+ /* Main shrinkwrap function */
+ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedMesh *dm, float (*vertexCos)[3], int numVerts)
+ {
+       ShrinkwrapCalcData calc = NULL_ShrinkwrapCalcData;
+       //remove loop dependencies on derived meshs (TODO should this be done elsewhere?)
+       if(smd->target == ob) smd->target = NULL;
+       if(smd->auxTarget == ob) smd->auxTarget = NULL;
+       //Configure Shrinkwrap calc data
+       calc.smd = smd;
+       calc.ob = ob;
+       calc.original = dm;
+       calc.numVerts = numVerts;
+       calc.vertexCos = vertexCos;
+       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) );
 -
 -              printf("Shrinkwrap (%s)%d over (%s)%d\n",
 -                      calc.ob->id.name,                       calc.numVerts,
 -                      calc.smd->target->id.name,      calc.target->getNumVerts(calc.target)
 -              );
 -
+               //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
+       }
+       //Projecting target defined - lets work!
+       if(calc.target)
+       {
 -              float lim = 1000; //TODO: we should use FLT_MAX here, but sweepsphere code isnt prepared for that
+               switch(smd->shrinkType)
+               {
+                       case MOD_SHRINKWRAP_NEAREST_SURFACE:
+                               BENCH(shrinkwrap_calc_nearest_surface_point(&calc));
+                       break;
+                       case MOD_SHRINKWRAP_PROJECT:
+                               BENCH(shrinkwrap_calc_normal_projection(&calc));
+                       break;
+                       case MOD_SHRINKWRAP_NEAREST_VERTEX:
+                               BENCH(shrinkwrap_calc_nearest_vertex(&calc));
+                       break;
+               }
+       }
+       //free memory
+       if(calc.target)
+               calc.target->release( calc.target );
+ }
+ /*
+  * Shrinkwrap to the nearest vertex
+  *
+  * it builds a kdtree of vertexs we can attach to and then
+  * for each vertex performs a nearest vertex search on the tree
+  */
+ void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc)
+ {
+       int i;
+       const int vgroup                 = get_named_vertexgroup_num(calc->ob, calc->smd->vgroup_name);
+       MDeformVert *const dvert = calc->original ? calc->original->getVertDataArray(calc->original, CD_MDEFORMVERT) : NULL;
+       BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh;
+       BVHTreeNearest  nearest  = NULL_BVHTreeNearest;
+       BENCH(bvhtree_from_mesh_verts(&treeData, calc->target, 0.0, 2, 6));
+       if(treeData.tree == NULL) return OUT_OF_MEMORY();
+       //Setup nearest
+       nearest.index = -1;
+       nearest.dist = FLT_MAX;
+ #pragma omp parallel for default(none) private(i) firstprivate(nearest) shared(treeData,calc) schedule(static)
+       for(i = 0; i<calc->numVerts; ++i)
+       {
+               float *co = calc->vertexCos[i];
+               float tmp_co[3];
+               float weight = vertexgroup_get_vertex_weight(dvert, i, vgroup);
+               if(weight == 0.0f) continue;
+               VECCOPY(tmp_co, co);
+               space_transform_apply(&calc->local2target, tmp_co); //Convert the coordinates to the tree coordinates
+               //Use local proximity heuristics (to reduce the nearest search)
+               //
+               //If we already had an hit before.. we assume this vertex is going to have a close hit to that other vertex
+               //so we can initiate the "nearest.dist" with the expected value to that last hit.
+               //This will lead in prunning of the search tree.
+               if(nearest.index != -1)
+                       nearest.dist = squared_dist(tmp_co, nearest.co);
+               else
+                       nearest.dist = FLT_MAX;
+               BLI_bvhtree_find_nearest(treeData.tree, tmp_co, &nearest, treeData.nearest_callback, &treeData);
+               //Found the nearest vertex
+               if(nearest.index != -1)
+               {
+                       //Adjusting the vertex weight, so that after interpolating it keeps a certain distance from the nearest position
+                       float dist = sasqrt(nearest.dist);
+                       if(dist > FLT_EPSILON) weight *= (dist - calc->keepDist)/dist;
+                       //Convert the coordinates back to mesh coordinates
+                       VECCOPY(tmp_co, nearest.co);
+                       space_transform_invert(&calc->local2target, tmp_co);
+                       VecLerpf(co, co, tmp_co, weight);       //linear interpolation
+               }
+       }
+       free_bvhtree_from_mesh(&treeData);
+ }
+ /*
+  * This function raycast a single vertex and updates the hit if the "hit" is considered valid.
+  * Returns TRUE if "hit" was updated.
+  * Opts control whether an hit is valid or not
+  * Supported options are:
+  *    MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE (front faces hits are ignored)
+  *    MOD_SHRINKWRAP_CULL_TARGET_BACKFACE (back faces hits are ignored)
+  */
+ int normal_projection_project_vertex(char options, const float *vert, const float *dir, const SpaceTransform *transf, BVHTree *tree, BVHTreeRayHit *hit, BVHTree_RayCastCallback callback, void *userdata)
+ {
+       float tmp_co[3], tmp_no[3];
+       const float *co, *no;
+       BVHTreeRayHit hit_tmp;
+       //Copy from hit (we need to convert hit rays from one space coordinates to the other
+       memcpy( &hit_tmp, hit, sizeof(hit_tmp) );
+       //Apply space transform (TODO readjust dist)
+       if(transf)
+       {
+               VECCOPY( tmp_co, vert );
+               space_transform_apply( transf, tmp_co );
+               co = tmp_co;
+               VECCOPY( tmp_no, dir );
+               space_transform_apply_normal( transf, tmp_no );
+               no = tmp_no;
+               hit_tmp.dist *= Mat4ToScalef( transf->local2target );
+       }
+       else
+       {
+               co = vert;
+               no = dir;
+       }
+       hit_tmp.index = -1;
+       BLI_bvhtree_ray_cast(tree, co, no, &hit_tmp, callback, userdata);
+       if(hit_tmp.index != -1)
+       {
+               float dot = INPR( dir, hit_tmp.no);
+               if(((options & MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE) && dot <= 0.0f)
+               || ((options & MOD_SHRINKWRAP_CULL_TARGET_BACKFACE) && dot >= 0.0f))
+                       return FALSE; //Ignore hit
+               //Inverting space transform (TODO make coeherent with the initial dist readjust)
+               if(transf)
+               {
+                       space_transform_invert( transf, hit_tmp.co );
+                       space_transform_invert_normal( transf, hit_tmp.no );
+                       hit_tmp.dist = VecLenf( vert, hit_tmp.co );
+               }
+               memcpy(hit, &hit_tmp, sizeof(hit_tmp) );
+               return TRUE;
+       }
+       return FALSE;
+ }
+ 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;
+       //Vertex group data
+       const int vgroup                   = get_named_vertexgroup_num(calc->ob, calc->smd->vgroup_name);
+       const MDeformVert *dvert = calc->original ? calc->original->getVertDataArray(calc->original, CD_MDEFORMVERT) : NULL;
+       //Raycast and tree stuff
+       BVHTreeRayHit hit;
+       BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh;        //target
+       //auxiliar target
+       DerivedMesh * aux_mesh = NULL;
+       BVHTreeFromMesh auxData= NULL_BVHTreeFromMesh;
+       SpaceTransform local2aux;
+ do
+ {
+       //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;
+       }
+       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
+               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; 
+       }
+       //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)
+       {
+               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)
+       {
+               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(dvert, i, vgroup);
+               if(weight == 0.0f) continue;
+               if(ss_mesh)
+               {
+                       VECCOPY(tmp_co, vert[i].co);
+               }
+               else
+               {
+                       VECCOPY(tmp_co, co);
+               }
+               if(vert)
+                       NormalShortToFloat(tmp_no, vert[i].no);
+               else
+                       VECCOPY( tmp_no, proj_axis );
+               hit.index = -1;
+               hit.dist = lim;
+               //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);
+                       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] };
+                       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);
+               }
+               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);
+ }
+ /*
+  * Shrinkwrap moving vertexs to the nearest surface point on the target
+  *
+  * it builds a BVHTree from the target mesh and then performs a
+  * NN matchs for each vertex
+  */
+ void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc)
+ {
+       int i;
+       const int vgroup = get_named_vertexgroup_num(calc->ob, calc->smd->vgroup_name);
+       const MDeformVert *const dvert = calc->original ? calc->original->getVertDataArray(calc->original, CD_MDEFORMVERT) : NULL;
+       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) return OUT_OF_MEMORY();
+       //Setup nearest
+       nearest.index = -1;
+       nearest.dist = FLT_MAX;
+       //Find the nearest vertex
+ #pragma omp parallel for default(none) private(i) firstprivate(nearest) shared(calc,treeData) schedule(static)
+       for(i = 0; i<calc->numVerts; ++i)
+       {
+               float *co = calc->vertexCos[i];
+               float tmp_co[3];
+               float weight = vertexgroup_get_vertex_weight(dvert, i, vgroup);
+               if(weight == 0.0f) continue;
+               //Convert the vertex to tree coordinates
+               VECCOPY(tmp_co, co);
+               space_transform_apply(&calc->local2target, tmp_co);
+               //Use local proximity heuristics (to reduce the nearest search)
+               //
+               //If we already had an hit before.. we assume this vertex is going to have a close hit to that other vertex
+               //so we can initiate the "nearest.dist" with the expected value to that last hit.
+               //This will lead in prunning of the search tree.
+               if(nearest.index != -1)
+                       nearest.dist = squared_dist(tmp_co, nearest.co);
+               else
+                       nearest.dist = FLT_MAX;
+               BLI_bvhtree_find_nearest(treeData.tree, tmp_co, &nearest, treeData.nearest_callback, &treeData);
+               //Found the nearest vertex
+               if(nearest.index != -1)
+               {
+                       if(calc->smd->shrinkOpts & MOD_SHRINKWRAP_KEEP_ABOVE_SURFACE)
+                       {
+                               //Make the vertex stay on the front side of the face
+                               VECADDFAC(tmp_co, nearest.co, nearest.no, calc->keepDist);
+                       }
+                       else
+                       {
+                               //Adjusting the vertex weight, so that after interpolating it keeps a certain distance from the nearest position
+                               float dist = sasqrt( nearest.dist );
+                               if(dist > FLT_EPSILON)
+                                       VecLerpf(tmp_co, tmp_co, nearest.co, (dist - calc->keepDist)/dist);     //linear interpolation
+                               else
+                                       VECCOPY( tmp_co, nearest.co );
+                       }
+                       //Convert the coordinates back to mesh coordinates
+                       space_transform_invert(&calc->local2target, tmp_co);
+                       VecLerpf(co, co, tmp_co, weight);       //linear interpolation
+               }
+       }
+       free_bvhtree_from_mesh(&treeData);
+ }
index d8cc7633fb3b7cfd20266830a572c6602628b125,0f820e8854120519717722f1dab86f5a6a0b6cbb..9599cc1d247f6008bb0c81b8be7ced066269e551
@@@ -35,6 -35,8 +35,7 @@@ typedef enum ModifierType 
        eModifierType_Cloth,
        eModifierType_Collision,
        eModifierType_Bevel,
 -      eModifierType_SimpleDeform,
+       eModifierType_Shrinkwrap,
        NUM_MODIFIER_TYPES
  } ModifierType;
  
@@@ -491,4 -493,73 +492,45 @@@ typedef struct ExplodeModifierData 
        float protect;
  } ExplodeModifierData;
  
 -
 -typedef struct SimpleDeformModifierData {
 -      ModifierData modifier;
 -
 -      struct Object *origin;  /* object to control the origin of modifier space coordinates */
 -      char vgroup_name[32];   /* optional vertexgroup name */
 -      float factor;                   /* factors to control simple deforms */
 -      float limit[2];                 /* lower and upper limit */             
 -
 -      char mode;                              /* deform function */
 -      char axis;                              /* lock axis (for taper and strech) */
 -      char originOpts;                /* originOptions */
 -      char pad;
 -
 -} SimpleDeformModifierData;
 -
 -#define MOD_SIMPLEDEFORM_MODE_TWIST           1
 -#define MOD_SIMPLEDEFORM_MODE_BEND            2
 -#define MOD_SIMPLEDEFORM_MODE_TAPER           3
 -#define MOD_SIMPLEDEFORM_MODE_STRETCH 4
 -
 -#define MOD_SIMPLEDEFORM_LOCK_AXIS_X                  (1<<0)
 -#define MOD_SIMPLEDEFORM_LOCK_AXIS_Y                  (1<<1)
 -
 -/* indicates whether simple deform should use the local
 -   coordinates or global coordinates of origin */
 -#define MOD_SIMPLEDEFORM_ORIGIN_LOCAL                 (1<<0)
 -
+ typedef struct ShrinkwrapModifierData {
+       ModifierData modifier;
+       struct Object *target;  /* shrink target */
+       struct Object *auxTarget; /* additional shrink target */
+       char vgroup_name[32];   /* optional vertexgroup name */
+       float keepDist;                 /* distance offset to keep from mesh/projection point */
+       short shrinkType;               /* shrink type projection */
+       short shrinkOpts;               /* shrink options */
+       char projAxis;                  /* axis to project over */
+       /*
+        * if using projection over vertex normal this controls the
+        * the level of subsurface that must be done before getting the
+        * vertex coordinates and normal
+        */
+       char subsurfLevels;
+       char pad[6];
+ } ShrinkwrapModifierData;
+ /* Shrinkwrap->shrinkType */
+ #define MOD_SHRINKWRAP_NEAREST_SURFACE        0
+ #define MOD_SHRINKWRAP_PROJECT                        1
+ #define MOD_SHRINKWRAP_NEAREST_VERTEX 2
+ /* Shrinkwrap->shrinkOpts */
+ #define MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR  (1<<0)  /* allow shrinkwrap to move the vertex in the positive direction of axis */
+ #define MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR  (1<<1)  /* allow shrinkwrap to move the vertex in the negative direction of axis */
+ #define MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE  (1<<3)  /* ignore vertex moves if a vertex ends projected on a front face of the target */
+ #define MOD_SHRINKWRAP_CULL_TARGET_BACKFACE           (1<<4)  /* ignore vertex moves if a vertex ends projected on a back face of the target */
+ #define MOD_SHRINKWRAP_KEEP_ABOVE_SURFACE             (1<<5)  /* distance is measure to the front face of the target */
+ #define MOD_SHRINKWRAP_PROJECT_OVER_X_AXIS            (1<<0)
+ #define MOD_SHRINKWRAP_PROJECT_OVER_Y_AXIS            (1<<1)
+ #define MOD_SHRINKWRAP_PROJECT_OVER_Z_AXIS            (1<<2)
+ #define MOD_SHRINKWRAP_PROJECT_OVER_NORMAL                    0       /* projection over normal is used if no axis is selected */
  #endif
index 27ddca1aaa5ecce07ee1f981c58f92e5325ed349,4682549297a15f56b0c084bb909a2f46b91b3c33..76f244db6fc27ab7e2b2463289f2e58e4f3fe6b9
@@@ -1826,6 -1873,24 +1826,16 @@@ static void draw_modifier(uiBlock *bloc
                        height = 94;
                } else if (md->type==eModifierType_Explode) {
                        height = 94;
 -
 -              } else if (md->type==eModifierType_SimpleDeform) {
 -                      SimpleDeformModifierData *smd = (SimpleDeformModifierData*) md;
 -                      height += 19*4;
 -                      if(smd->origin != NULL) height += 19;
 -                      if(smd->mode == MOD_SIMPLEDEFORM_MODE_STRETCH
 -                      || smd->mode == MOD_SIMPLEDEFORM_MODE_TAPER  )
 -                              height += 19;
+               } else if (md->type==eModifierType_Shrinkwrap) {
+                       ShrinkwrapModifierData *smd = (ShrinkwrapModifierData*) md;
+                       height = 86 + 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;
                }
                                                        /* roundbox 4 free variables: corner-rounding, nop, roundbox type, shade */
                uiDefBut(block, ROUNDBOX, 0, "", x-10, y-height-2, width, height-2, NULL, 5.0, 0.0, 12, 40, ""); 
                        uiDefButBitS(block, TOG, eExplodeFlag_Alive, B_MODIFIER_RECALC, "Alive",        lx+buttonWidth/3, cy, buttonWidth/3,19, &emd->flag, 0, 0, 0, 0, "Show mesh when particles are alive");
                        uiDefButBitS(block, TOG, eExplodeFlag_Dead, B_MODIFIER_RECALC, "Dead",  lx+buttonWidth*2/3, cy, buttonWidth/3,19, &emd->flag, 0, 0, 0, 0, "Show mesh when particles are dead");
                        uiBlockEndAlign(block);
 -              } else if (md->type==eModifierType_SimpleDeform) {
 -                      SimpleDeformModifierData *smd = (SimpleDeformModifierData*) md;
 -
 -                      but=uiDefBut(block, TEX, B_MODIFIER_RECALC, "VGroup: ",         lx, (cy-=19), buttonWidth,19, &smd->vgroup_name, 0, 31, 0, 0, "Vertex Group name");
 -                      uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)ob);
 -
 -                      uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CHANGEDEP, "Ob: ",      lx, (cy-=19), buttonWidth,19, &smd->origin, "Origin of modifier space coordinates");
 -                      if(smd->origin != NULL)
 -                              uiDefButBitC(block, TOG, MOD_SIMPLEDEFORM_ORIGIN_LOCAL, B_MODIFIER_RECALC, "Relative",lx,(cy-=19),buttonWidth,19, &smd->originOpts, 0, 0, 0, 0, "Sets the origin of deform space to be relative to the object");
 -
 -                      uiDefButF(block, NUM, B_MODIFIER_RECALC, "Factor:",     lx,(cy-=19),buttonWidth,19, &smd->factor, -10.0f, 10.0f, 0.5f, 0, "Deform Factor");
 -
 -                      uiDefButF(block, NUM, B_MODIFIER_RECALC, "Upper Limit:",        lx,(cy-=19),buttonWidth,19, &smd->limit[1], -1000.0f, 1000.0f, 5.0f, 0, "Upper Limit Bend on X");
 -                      uiDefButF(block, NUM, B_MODIFIER_RECALC, "Lower Limit:",        lx,(cy-=19),buttonWidth,19, &smd->limit[0], -1000.0f, 1000.0f, 5.0f, 0, "Lower Limit Bend on X");
 -
 -                      if(smd->mode == MOD_SIMPLEDEFORM_MODE_STRETCH
 -                      || smd->mode == MOD_SIMPLEDEFORM_MODE_TAPER  )
 -                      {
 -                              uiDefButBitC(block, TOG, MOD_SIMPLEDEFORM_LOCK_AXIS_X, B_MODIFIER_RECALC, "Loc X", lx,             (cy-=19),buttonWidth/2,19, &smd->axis, 0, 0, 0, 0, "Disallow changes on the X coordinate");
 -                              uiDefButBitC(block, TOG, MOD_SIMPLEDEFORM_LOCK_AXIS_Y, B_MODIFIER_RECALC, "Loc Y", lx+(buttonWidth/2), (cy),buttonWidth/2,19, &smd->axis, 0, 0, 0, 0, "Disallow changes on the Y coordinate");
 -                      }
+               } else if (md->type==eModifierType_Shrinkwrap) {
+                       ShrinkwrapModifierData *smd = (ShrinkwrapModifierData*) md;
+                       char shrinktypemenu[]="Shrinkwrap type%t|nearest surface point %x0|projection %x1|nearest vertex %x2";
+                       uiDefIDPoinBut(block, modifier_testMeshObj, ID_OB, B_CHANGEDEP, "Ob: ", lx, (cy-=19), buttonWidth,19, &smd->target, "Target to shrink to");
+                       but=uiDefBut(block, TEX, B_MODIFIER_RECALC, "VGroup: ",         lx, (cy-=19), buttonWidth,19, &smd->vgroup_name, 0, 31, 0, 0, "Vertex Group name");
+                       uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)ob);
+                       uiDefButF(block, NUM, B_MODIFIER_RECALC, "Offset:",     lx,(cy-=19),buttonWidth,19, &smd->keepDist, 0.0f, 100.0f, 1.0f, 0, "Specify distance to keep from the target");
+                       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.");
+                       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");
+                               uiDefButBitC(block, TOG, MOD_SHRINKWRAP_PROJECT_OVER_Z_AXIS, B_MODIFIER_RECALC, "Z",    lx+buttonWidth/3*2,cy,buttonWidth/3,19, &smd->projAxis, 0, 0, 0, 0, "Projection over Z axis");
+                               /* allowed directions of projection axis */
+                               uiDefButBitS(block, TOG, MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR, B_MODIFIER_RECALC, "Negative",   lx,(cy-=19),buttonWidth/2,19, &smd->shrinkOpts, 0, 0, 0, 0, "Allows to move the vertex in the negative direction of axis");
+                               uiDefButBitS(block, TOG, MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR, B_MODIFIER_RECALC, "Positive",   lx + buttonWidth/2,cy,buttonWidth/2,19, &smd->shrinkOpts, 0, 0, 0, 0, "Allows to move the vertex in the positive direction of axis");
+                               uiDefButBitS(block, TOG, MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE, B_MODIFIER_RECALC, "Cull frontfaces",lx,(cy-=19),buttonWidth/2,19, &smd->shrinkOpts, 0, 0, 0, 0, "Controls whether a vertex can be projected to a front face on target");
+                               uiDefButBitS(block, TOG, MOD_SHRINKWRAP_CULL_TARGET_BACKFACE,  B_MODIFIER_RECALC, "Cull backfaces",     lx+buttonWidth/2,cy,buttonWidth/2,19, &smd->shrinkOpts, 0, 0, 0, 0, "Controls whether a vertex can be projected to a back face on target");
+                               uiDefIDPoinBut(block, modifier_testMeshObj, ID_OB, B_CHANGEDEP, "Ob2: ",        lx, (cy-=19), buttonWidth,19, &smd->auxTarget, "Aditional mesh to project over");
+                       }
+                       else if (smd->shrinkType == MOD_SHRINKWRAP_NEAREST_SURFACE){
+                               uiDefButBitS(block, TOG, MOD_SHRINKWRAP_KEEP_ABOVE_SURFACE, B_MODIFIER_RECALC, "Above surface", lx,(cy-=19),buttonWidth,19, &smd->shrinkOpts, 0, 0, 0, 0, "Vertices are kept on the front side of faces");
+                       }
+                       uiBlockEndAlign(block);
                }
  
 -
                uiBlockEndAlign(block);
  
                y-=height;