use static functions where possible for some local functions.
[blender.git] / source / blender / blenkernel / intern / cloth.c
index d41ad6a4abf292c41da335e64651a7368dd02a51..9ee6be903fa7ceb338ffba306bc3a0bf851fcd33 100644 (file)
@@ -1,15 +1,12 @@
 /*  cloth.c
 *
 *
-* ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+* ***** 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. The Blender
-* Foundation also sells licenses for use in proprietary software under
-* the Blender License.  See http://www.blender.org/BL/ for information
-* about this.
+* 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
@@ -25,7 +22,7 @@
 *
 * Contributor(s): Daniel Genrich
 *
-* ***** END GPL/BL DUAL LICENSE BLOCK *****
+* ***** END GPL LICENSE BLOCK *****
 */
 
 #include "MEM_guardedalloc.h"
@@ -36,6 +33,7 @@
 #include "DNA_mesh_types.h"
 #include "DNA_object_force.h"
 #include "DNA_scene_types.h"
+#include "DNA_particle_types.h"
 
 #include "BKE_deform.h"
 #include "BKE_DerivedMesh.h"
 #include "BKE_object.h"
 #include "BKE_modifier.h"
 #include "BKE_utildefines.h"
+#include "BKE_particle.h"
 
 #include "BKE_pointcache.h"
 
+#include "BLI_kdopbvh.h"
+
 #ifdef _WIN32
 void tstart ( void )
 {}
@@ -94,7 +95,7 @@ static CM_SOLVER_DEF  solvers [] =
 static void cloth_to_object (Object *ob,  ClothModifierData *clmd, DerivedMesh *dm);
 static void cloth_from_mesh ( Object *ob, ClothModifierData *clmd, DerivedMesh *dm );
 static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *dm, float framenr, int first);
-int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm );
+static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm );
 static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm );
 
 
@@ -133,7 +134,7 @@ void cloth_init ( ClothModifierData *clmd )
        
        clmd->coll_parms->self_friction = 5.0;
        clmd->coll_parms->friction = 5.0;
-       clmd->coll_parms->loop_count = 3;
+       clmd->coll_parms->loop_count = 2;
        clmd->coll_parms->epsilon = 0.015f;
        clmd->coll_parms->flags = CLOTH_COLLSETTINGS_FLAG_ENABLED;
        clmd->coll_parms->collision_list = NULL;
@@ -154,13 +155,14 @@ void cloth_init ( ClothModifierData *clmd )
        clmd->sim_parms->goalfrict = 0.0f;
 }
 
-
-BVH *bvh_build_from_cloth (ClothModifierData *clmd, float epsilon)
+static BVHTree *bvhselftree_build_from_cloth (ClothModifierData *clmd, float epsilon)
 {
-       unsigned int i = 0;
-       BVH     *bvh=NULL;
-       Cloth *cloth = clmd->clothObject;
-       ClothVertex *verts = NULL;
+       unsigned int i;
+       BVHTree *bvhtree;
+       Cloth *cloth;
+       ClothVertex *verts;
+       MFace *mfaces;
+       float co[12];
 
        if(!clmd)
                return NULL;
@@ -171,107 +173,171 @@ BVH *bvh_build_from_cloth (ClothModifierData *clmd, float epsilon)
                return NULL;
        
        verts = cloth->verts;
+       mfaces = cloth->mfaces;
        
        // in the moment, return zero if no faces there
-       if(!cloth->numfaces)
+       if(!cloth->numverts)
                return NULL;
        
-       bvh = MEM_callocN(sizeof(BVH), "BVH");
-       if (bvh == NULL) 
+       // create quadtree with k=26
+       bvhtree = BLI_bvhtree_new(cloth->numverts, epsilon, 4, 6);
+       
+       // fill tree
+       for(i = 0; i < cloth->numverts; i++, verts++)
        {
-               printf("bvh: Out of memory.\n");
-               return NULL;
+               VECCOPY(&co[0*3], verts->xold);
+               
+               BLI_bvhtree_insert(bvhtree, i, co, 1);
        }
        
-       // springs = cloth->springs;
-       // numsprings = cloth->numsprings;
+       // balance tree
+       BLI_bvhtree_balance(bvhtree);
+       
+       return bvhtree;
+}
+
+static BVHTree *bvhtree_build_from_cloth (ClothModifierData *clmd, float epsilon)
+{
+       unsigned int i;
+       BVHTree *bvhtree;
+       Cloth *cloth;
+       ClothVertex *verts;
+       MFace *mfaces;
+       float co[12];
+
+       if(!clmd)
+               return NULL;
 
-       bvh->epsilon = epsilon;
-       bvh->numfaces = cloth->numfaces;
-       bvh->mfaces = cloth->mfaces;
+       cloth = clmd->clothObject;
 
-       bvh->numverts = cloth->numverts;
+       if(!cloth)
+               return NULL;
        
-       bvh->current_x = MEM_callocN ( sizeof ( MVert ) * bvh->numverts, "bvh->current_x" );
+       verts = cloth->verts;
+       mfaces = cloth->mfaces;
        
-       if (bvh->current_x == NULL) 
-       {
-               printf("bvh: Out of memory.\n");
-               MEM_freeN(bvh);
+       // in the moment, return zero if no faces there
+       if(!cloth->numfaces)
                return NULL;
-       }
        
-       for(i = 0; i < bvh->numverts; i++)
+       // create quadtree with k=26
+       bvhtree = BLI_bvhtree_new(cloth->numfaces, epsilon, 4, 26);
+       
+       // fill tree
+       for(i = 0; i < cloth->numfaces; i++, mfaces++)
        {
-               VECCOPY(bvh->current_x[i].co, verts[i].tx);
+               VECCOPY(&co[0*3], verts[mfaces->v1].xold);
+               VECCOPY(&co[1*3], verts[mfaces->v2].xold);
+               VECCOPY(&co[2*3], verts[mfaces->v3].xold);
+               
+               if(mfaces->v4)
+                       VECCOPY(&co[3*3], verts[mfaces->v4].xold);
+               
+               BLI_bvhtree_insert(bvhtree, i, co, (mfaces->v4 ? 4 : 3));
        }
        
-       bvh_build (bvh);
+       // balance tree
+       BLI_bvhtree_balance(bvhtree);
        
-       return bvh;
+       return bvhtree;
 }
 
-void bvh_update_from_cloth(ClothModifierData *clmd, int moving)
-{
+void bvhtree_update_from_cloth(ClothModifierData *clmd, int moving)
+{      
        unsigned int i = 0;
        Cloth *cloth = clmd->clothObject;
-       BVH *bvh = cloth->tree;
+       BVHTree *bvhtree = cloth->bvhtree;
        ClothVertex *verts = cloth->verts;
+       MFace *mfaces;
+       float co[12], co_moving[12];
+       int ret = 0;
        
-       if(!bvh)
+       if(!bvhtree)
                return;
        
-       if(cloth->numverts!=bvh->numverts)
-               return;
+       mfaces = cloth->mfaces;
        
-       if(cloth->verts)
+       // update vertex position in bvh tree
+       if(verts && mfaces)
        {
-               for(i = 0; i < bvh->numverts; i++)
+               for(i = 0; i < cloth->numfaces; i++, mfaces++)
                {
-                       VECCOPY(bvh->current_x[i].co, verts[i].tx);
-                       VECCOPY(bvh->current_xold[i].co, verts[i].txold);
+                       VECCOPY(&co[0*3], verts[mfaces->v1].txold);
+                       VECCOPY(&co[1*3], verts[mfaces->v2].txold);
+                       VECCOPY(&co[2*3], verts[mfaces->v3].txold);
+                       
+                       if(mfaces->v4)
+                               VECCOPY(&co[3*3], verts[mfaces->v4].txold);
+               
+                       // copy new locations into array
+                       if(moving)
+                       {
+                               // update moving positions
+                               VECCOPY(&co_moving[0*3], verts[mfaces->v1].tx);
+                               VECCOPY(&co_moving[1*3], verts[mfaces->v2].tx);
+                               VECCOPY(&co_moving[2*3], verts[mfaces->v3].tx);
+                               
+                               if(mfaces->v4)
+                                       VECCOPY(&co_moving[3*3], verts[mfaces->v4].tx);
+                               
+                               ret = BLI_bvhtree_update_node(bvhtree, i, co, co_moving, (mfaces->v4 ? 4 : 3));
+                       }
+                       else
+                       {
+                               ret = BLI_bvhtree_update_node(bvhtree, i, co, NULL, (mfaces->v4 ? 4 : 3));
+                       }
+                       
+                       // check if tree is already full
+                       if(!ret)
+                               break;
                }
+               
+               BLI_bvhtree_update_tree(bvhtree);
        }
-       
-       bvh_update(bvh, moving);
 }
 
-int modifiers_indexInObject(Object *ob, ModifierData *md_seek);
-
-int cloth_read_cache(Object *ob, ClothModifierData *clmd, float framenr)
-{
-       PTCacheID pid;
-       PTCacheFile *pf;
+void bvhselftree_update_from_cloth(ClothModifierData *clmd, int moving)
+{      
+       unsigned int i = 0;
        Cloth *cloth = clmd->clothObject;
-       unsigned int a, ret = 1;
+       BVHTree *bvhtree = cloth->bvhselftree;
+       ClothVertex *verts = cloth->verts;
+       MFace *mfaces;
+       float co[12], co_moving[12];
+       int ret = 0;
        
-       if(!cloth)
-               return 0;
+       if(!bvhtree)
+               return;
        
-       BKE_ptcache_id_from_cloth(&pid, ob, clmd);
-       pf = BKE_ptcache_file_open(&pid, PTCACHE_FILE_READ, framenr);
-       if(pf) {
-               for(a = 0; a < cloth->numverts; a++) {
-                       if(!BKE_ptcache_file_read_floats(pf, cloth->verts[a].x, 3)) {
-                               ret = 0;
-                               break;
+       mfaces = cloth->mfaces;
+       
+       // update vertex position in bvh tree
+       if(verts && mfaces)
+       {
+               for(i = 0; i < cloth->numverts; i++, verts++)
+               {
+                       VECCOPY(&co[0*3], verts->txold);
+                       
+                       // copy new locations into array
+                       if(moving)
+                       {
+                               // update moving positions
+                               VECCOPY(&co_moving[0*3], verts->tx);
+                               
+                               ret = BLI_bvhtree_update_node(bvhtree, i, co, co_moving, 1);
                        }
-                       if(!BKE_ptcache_file_read_floats(pf, cloth->verts[a].xconst, 3)) {
-                               ret = 0;
-                               break;
+                       else
+                       {
+                               ret = BLI_bvhtree_update_node(bvhtree, i, co, NULL, 1);
                        }
-                       if(!BKE_ptcache_file_read_floats(pf, cloth->verts[a].v, 3)) {
-                               ret = 0;
+                       
+                       // check if tree is already full
+                       if(!ret)
                                break;
-                       }
                }
                
-               BKE_ptcache_file_close(pf);
+               BLI_bvhtree_update_tree(bvhtree);
        }
-       else
-               ret = 0;
-       
-       return ret;
 }
 
 void cloth_clear_cache(Object *ob, ClothModifierData *clmd, float framenr)
@@ -281,36 +347,12 @@ void cloth_clear_cache(Object *ob, ClothModifierData *clmd, float framenr)
        BKE_ptcache_id_from_cloth(&pid, ob, clmd);
 
        // don't do anything as long as we're in editmode!
-       if(pid.cache->flag & PTCACHE_BAKE_EDIT_ACTIVE)
+       if(pid.cache->edit && ob->mode & OB_MODE_PARTICLE_EDIT)
                return;
        
        BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_AFTER, framenr);
 }
 
-void cloth_write_cache(Object *ob, ClothModifierData *clmd, float framenr)
-{
-       Cloth *cloth = clmd->clothObject;
-       PTCacheID pid;
-       PTCacheFile *pf;
-       unsigned int a;
-       
-       if(!cloth)
-               return;
-       
-       BKE_ptcache_id_from_cloth(&pid, ob, clmd);
-       pf = BKE_ptcache_file_open(&pid, PTCACHE_FILE_WRITE, framenr);
-       if(!pf)
-               return;
-       
-       for(a = 0; a < cloth->numverts; a++) {
-               BKE_ptcache_file_write_floats(pf, cloth->verts[a].x, 3);
-               BKE_ptcache_file_write_floats(pf, cloth->verts[a].xconst, 3);
-               BKE_ptcache_file_write_floats(pf, cloth->verts[a].v, 3);
-       }
-       
-       BKE_ptcache_file_close(pf);
-}
-
 static int do_init_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *result, int framenr)
 {
        PointCache *cache;
@@ -369,7 +411,7 @@ static int do_step_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *resul
 
        tend();
 
-       /* printf ( "Cloth simulation time: %f\n", ( float ) tval() ); */
+       // printf ( "%f\n", ( float ) tval() );
        
        return ret;
 }
@@ -377,25 +419,28 @@ static int do_step_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *resul
 /************************************************
  * clothModifier_do - main simulation function
 ************************************************/
-DerivedMesh *clothModifier_do(ClothModifierData *clmd, Object *ob, DerivedMesh *dm, int useRenderParams, int isFinalCalc)
+DerivedMesh *clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, DerivedMesh *dm, int useRenderParams, int isFinalCalc)
 {
        DerivedMesh *result;
        PointCache *cache;
        PTCacheID pid;
        float timescale;
        int framedelta, framenr, startframe, endframe;
+       int cache_result;
 
-       framenr= (int)G.scene->r.cfra;
+       clmd->scene= scene;     /* nice to pass on later :) */
+       framenr= (int)scene->r.cfra;
        cache= clmd->point_cache;
        result = CDDM_copy(dm);
 
        BKE_ptcache_id_from_cloth(&pid, ob, clmd);
-       BKE_ptcache_id_time(&pid, framenr, &startframe, &endframe, &timescale);
+       BKE_ptcache_id_time(&pid, scene, framenr, &startframe, &endframe, &timescale);
        clmd->sim_parms->timescale= timescale;
 
        if(!result) {
                cache->flag &= ~PTCACHE_SIMULATION_VALID;
                cache->simframe= 0;
+               cache->last_exact= 0;
                return dm;
        }
        
@@ -407,6 +452,7 @@ DerivedMesh *clothModifier_do(ClothModifierData *clmd, Object *ob, DerivedMesh *
                if(result->getNumVerts(result) != clmd->clothObject->numverts) {
                        cache->flag &= ~PTCACHE_SIMULATION_VALID;
                        cache->simframe= 0;
+                       cache->last_exact= 0;
                        return result;
                }
        }
@@ -418,6 +464,7 @@ DerivedMesh *clothModifier_do(ClothModifierData *clmd, Object *ob, DerivedMesh *
        if(BKE_ptcache_get_continue_physics()) {
                cache->flag &= ~PTCACHE_SIMULATION_VALID;
                cache->simframe= 0;
+               cache->last_exact= 0;
 
                /* do simulation */
                if(!do_init_cloth(ob, clmd, result, framenr))
@@ -433,6 +480,7 @@ DerivedMesh *clothModifier_do(ClothModifierData *clmd, Object *ob, DerivedMesh *
        if(framenr < startframe) {
                cache->flag &= ~PTCACHE_SIMULATION_VALID;
                cache->simframe= 0;
+               cache->last_exact= 0;
                return result;
        }
        else if(framenr > endframe) {
@@ -448,52 +496,61 @@ DerivedMesh *clothModifier_do(ClothModifierData *clmd, Object *ob, DerivedMesh *
        if(!do_init_cloth(ob, clmd, result, framenr))
                return result;
 
-       /* try to read from cache */
-       if(cloth_read_cache(ob, clmd, framenr)) {
-               cache->flag |= PTCACHE_SIMULATION_VALID;
+       if(framenr == startframe) {
+               BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
+               do_init_cloth(ob, clmd, result, framenr);
                cache->simframe= framenr;
+               cache->flag |= PTCACHE_SIMULATION_VALID;
+               cache->flag &= ~PTCACHE_REDO_NEEDED;
+               return result;
+       }
 
+       /* try to read from cache */
+       cache_result = BKE_ptcache_read_cache(&pid, (float)framenr, scene->r.frs_sec);
+
+       if(cache_result == PTCACHE_READ_EXACT || cache_result == PTCACHE_READ_INTERPOLATED) {
                implicit_set_positions(clmd);
                cloth_to_object (ob, clmd, result);
 
+               cache->simframe= framenr;
+               cache->flag |= PTCACHE_SIMULATION_VALID;
+
+               if(cache_result == PTCACHE_READ_INTERPOLATED && cache->flag & PTCACHE_REDO_NEEDED)
+                       BKE_ptcache_write_cache(&pid, framenr);
+
                return result;
        }
+       else if(cache_result==PTCACHE_READ_OLD) {
+               implicit_set_positions(clmd);
+               cache->flag |= PTCACHE_SIMULATION_VALID;
+       }
        else if(ob->id.lib || (cache->flag & PTCACHE_BAKED)) {
                /* if baked and nothing in cache, do nothing */
                cache->flag &= ~PTCACHE_SIMULATION_VALID;
                cache->simframe= 0;
+               cache->last_exact= 0;
                return result;
        }
 
-       if(framenr == startframe) {
-               cache->flag |= PTCACHE_SIMULATION_VALID;
-               cache->simframe= framenr;
-
-               /* don't write cache on first frame, but on second frame write
-                * cache for frame 1 and 2 */
-       }
-       else if(framedelta == 1) {
-               /* if on second frame, write cache for first frame */
-               if(framenr == startframe+1)
-                       cloth_write_cache(ob, clmd, startframe);
+       /* if on second frame, write cache for first frame */
+       if(cache->simframe == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact==0))
+               BKE_ptcache_write_cache(&pid, startframe);
 
-               /* do simulation */
-               cache->flag |= PTCACHE_SIMULATION_VALID;
-               cache->simframe= framenr;
+       clmd->sim_parms->timescale *= framenr - cache->simframe;
 
-               if(!do_step_cloth(ob, clmd, result, framenr)) {
-                       cache->flag &= ~PTCACHE_SIMULATION_VALID;
-                       cache->simframe= 0;
-               }
-               else
-                       cloth_write_cache(ob, clmd, framenr);
+       /* do simulation */
+       cache->flag |= PTCACHE_SIMULATION_VALID;
+       cache->simframe= framenr;
 
-               cloth_to_object (ob, clmd, result);
-       }
-       else {
+       if(!do_step_cloth(ob, clmd, result, framenr)) {
                cache->flag &= ~PTCACHE_SIMULATION_VALID;
                cache->simframe= 0;
+               cache->last_exact= 0;
        }
+       else
+               BKE_ptcache_write_cache(&pid, framenr);
+
+       cloth_to_object (ob, clmd, result);
 
        return result;
 }
@@ -544,8 +601,11 @@ void cloth_free_modifier ( Object *ob, ClothModifierData *clmd )
                cloth->numsprings = 0;
 
                // free BVH collision tree
-               if ( cloth->tree )
-                       bvh_free ( ( BVH * ) cloth->tree );
+               if ( cloth->bvhtree )
+                       BLI_bvhtree_free ( cloth->bvhtree );
+               
+               if ( cloth->bvhselftree )
+                       BLI_bvhtree_free ( cloth->bvhselftree );
 
                // we save our faces for collision objects
                if ( cloth->mfaces )
@@ -614,8 +674,11 @@ void cloth_free_modifier_extern ( ClothModifierData *clmd )
                cloth->numsprings = 0;
 
                // free BVH collision tree
-               if ( cloth->tree )
-                       bvh_free ( ( BVH * ) cloth->tree );
+               if ( cloth->bvhtree )
+                       BLI_bvhtree_free ( cloth->bvhtree );
+               
+               if ( cloth->bvhselftree )
+                       BLI_bvhtree_free ( cloth->bvhselftree );
 
                // we save our faces for collision objects
                if ( cloth->mfaces )
@@ -674,19 +737,18 @@ static void cloth_to_object (Object *ob,  ClothModifierData *clmd, DerivedMesh *
 /* can be optimized to do all groups in one loop */
 static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm )
 {
-       unsigned int i = 0;
-       unsigned int j = 0;
+       int i = 0;
+       int j = 0;
        MDeformVert *dvert = NULL;
        Cloth *clothObj = NULL;
-       unsigned int numverts = dm->getNumVerts ( dm );
+       int numverts;
        float goalfac = 0;
        ClothVertex *verts = NULL;
 
+       if (!clmd || !dm) return;
+
        clothObj = clmd->clothObject;
 
-       if ( !dm )
-               return;
-       
        numverts = dm->getNumVerts ( dm );
 
        verts = clothObj->verts;
@@ -749,11 +811,12 @@ static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm )
 
 static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *dm, float framenr, int first)
 {
-       unsigned int i = 0;
+       int i = 0;
        MVert *mvert = NULL;
        ClothVertex *verts = NULL;
        float tnull[3] = {0,0,0};
        Cloth *cloth = NULL;
+       float maxdist = 0;
 
        // If we have a clothObject, free it. 
        if ( clmd->clothObject != NULL )
@@ -813,6 +876,7 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d
                VECCOPY ( verts->xold, verts->x );
                VECCOPY ( verts->xconst, verts->x );
                VECCOPY ( verts->txold, verts->x );
+               VECCOPY ( verts->tx, verts->x );
                VecMulf ( verts->v, 0.0f );
 
                verts->impulse_count = 0;
@@ -822,8 +886,7 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d
        // apply / set vertex groups
        // has to be happen before springs are build!
        cloth_apply_vgroup (clmd, dm);
-       
-       
+
        if ( !cloth_build_springs ( clmd, dm ) )
        {
                cloth_free_modifier ( ob, clmd );
@@ -848,12 +911,18 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d
        if(!first)
                implicit_set_positions(clmd);
 
-       clmd->clothObject->tree = bvh_build_from_cloth ( clmd, clmd->coll_parms->epsilon );
+       clmd->clothObject->bvhtree = bvhtree_build_from_cloth ( clmd, clmd->coll_parms->epsilon );
+       
+       for(i = 0; i < dm->getNumVerts(dm); i++)
+       {
+               maxdist = MAX2(maxdist, clmd->coll_parms->selfepsilon* ( cloth->verts[i].avg_spring_len*2.0));
+       }
+       
+       clmd->clothObject->bvhselftree = bvhselftree_build_from_cloth ( clmd, maxdist );
 
        return 1;
 }
 
-
 static void cloth_from_mesh ( Object *ob, ClothModifierData *clmd, DerivedMesh *dm )
 {
        unsigned int numverts = dm->getNumVerts ( dm );
@@ -929,7 +998,7 @@ int cloth_add_spring ( ClothModifierData *clmd, unsigned int indexA, unsigned in
        return 0;
 }
 
-void cloth_free_errorsprings(Cloth *cloth, EdgeHash *edgehash, LinkNode **edgelist)
+static void cloth_free_errorsprings(Cloth *cloth, EdgeHash *edgehash, LinkNode **edgelist)
 {
        unsigned int i = 0;
        
@@ -962,18 +1031,18 @@ void cloth_free_errorsprings(Cloth *cloth, EdgeHash *edgehash, LinkNode **edgeli
                BLI_edgehash_free ( cloth->edgehash, NULL );
 }
 
-int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
+static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
 {
        Cloth *cloth = clmd->clothObject;
        ClothSpring *spring = NULL, *tspring = NULL, *tspring2 = NULL;
        unsigned int struct_springs = 0, shear_springs=0, bend_springs = 0;
-       unsigned int i = 0;
-       unsigned int numverts = dm->getNumVerts ( dm );
-       unsigned int numedges = dm->getNumEdges ( dm );
-       unsigned int numfaces = dm->getNumFaces ( dm );
+       int i = 0;
+       int numverts = dm->getNumVerts ( dm );
+       int numedges = dm->getNumEdges ( dm );
+       int numfaces = dm->getNumFaces ( dm );
        MEdge *medge = CDDM_get_edges ( dm );
        MFace *mface = CDDM_get_faces ( dm );
-       unsigned int index2 = 0; // our second vertex index
+       int index2 = 0; // our second vertex index
        LinkNode **edgelist = NULL;
        EdgeHash *edgehash = NULL;
        LinkNode *search = NULL, *search2 = NULL;