use static functions where possible for some local functions.
[blender.git] / source / blender / blenkernel / intern / cloth.c
index 38b4cf6bcbb46714285e9306f9d167271fe61108..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
 *
 * Contributor(s): Daniel Genrich
 *
-* ***** END GPL/BL DUAL LICENSE BLOCK *****
+* ***** END GPL LICENSE BLOCK *****
 */
 
-
-#include <math.h>
-#include <stdlib.h>
-#include <string.h>
-
 #include "MEM_guardedalloc.h"
 
-/* types */
-#include "DNA_curve_types.h"
-#include "DNA_object_types.h"
-#include "DNA_object_force.h"
+#include "BKE_cloth.h"
+
 #include "DNA_cloth_types.h"
-#include "DNA_key_types.h"
 #include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
-#include "DNA_lattice_types.h"
+#include "DNA_object_force.h"
 #include "DNA_scene_types.h"
-#include "DNA_modifier_types.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_arithb.h"
-#include "BLI_editVert.h"
-#include "BLI_edgehash.h"
-#include "BLI_linklist.h"
+#include "DNA_particle_types.h"
 
-#include "BKE_curve.h"
 #include "BKE_deform.h"
 #include "BKE_DerivedMesh.h"
 #include "BKE_cdderivedmesh.h"
-#include "BKE_displist.h"
 #include "BKE_effect.h"
 #include "BKE_global.h"
-#include "BKE_key.h"
-#include "BKE_mesh.h"
 #include "BKE_object.h"
-#include "BKE_cloth.h"
 #include "BKE_modifier.h"
 #include "BKE_utildefines.h"
-#include "BKE_DerivedMesh.h"
-#include "BIF_editdeform.h"
-#include "BIF_editkey.h"
-#include "DNA_screen_types.h"
-#include "BSE_headerbuttons.h"
-#include "BIF_screen.h"
-#include "BIF_space.h"
-#include "mydevice.h"
+#include "BKE_particle.h"
 
 #include "BKE_pointcache.h"
 
+#include "BLI_kdopbvh.h"
+
 #ifdef _WIN32
 void tstart ( void )
 {}
@@ -122,8 +94,8 @@ 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 cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm );
+static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *dm, float framenr, int first);
+static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm );
 static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm );
 
 
@@ -144,30 +116,25 @@ void cloth_init ( ClothModifierData *clmd )
        clmd->sim_parms->gravity [0] = 0.0;
        clmd->sim_parms->gravity [1] = 0.0;
        clmd->sim_parms->gravity [2] = -9.81;
-       clmd->sim_parms->structural = 30.0;
-       clmd->sim_parms->shear = 30.0;
-       clmd->sim_parms->bending = 1.0;
-       clmd->sim_parms->Cdis = 5.0;
+       clmd->sim_parms->structural = 15.0;
+       clmd->sim_parms->shear = 15.0;
+       clmd->sim_parms->bending = 0.5;
+       clmd->sim_parms->Cdis = 5.0; 
        clmd->sim_parms->Cvi = 1.0;
-       clmd->sim_parms->mass = 1.0f;
+       clmd->sim_parms->mass = 0.3f;
        clmd->sim_parms->stepsPerFrame = 5;
-       clmd->sim_parms->sim_time = 1.0;
        clmd->sim_parms->flags = 0;
        clmd->sim_parms->solver_type = 0;
        clmd->sim_parms->preroll = 0;
        clmd->sim_parms->maxspringlen = 10;
-       clmd->sim_parms->firstframe = 1;
-       clmd->sim_parms->lastframe = 250;
        clmd->sim_parms->vgroup_mass = 0;
-       clmd->sim_parms->lastcachedframe = 0;
-       clmd->sim_parms->editedframe = 0;
-       clmd->sim_parms->autoprotect = 25;
-       clmd->sim_parms->firstcachedframe = -1.0;
        clmd->sim_parms->avg_spring_len = 0.0;
+       clmd->sim_parms->presets = 2; /* cotton as start setting */
+       clmd->sim_parms->timescale = 1.0f; /* speed factor, describes how fast cloth moves */
        
        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;
@@ -184,17 +151,18 @@ void cloth_init ( ClothModifierData *clmd )
        clmd->sim_parms->maxgoal = 1.0f;
        clmd->sim_parms->mingoal = 0.0f;
        clmd->sim_parms->defgoal = 0.0f;
-       clmd->sim_parms->goalspring = 10.0f;
-       clmd->sim_parms->goalfrict = 5.0f;
+       clmd->sim_parms->goalspring = 1.0f;
+       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;
@@ -205,539 +173,385 @@ 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);
        
-       bvh->flags = 0;
-       bvh->leaf_tree = NULL;
-       bvh->leaf_root = NULL;
-       bvh->tree = NULL;
+       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" );
-       bvh->current_xold = MEM_callocN ( sizeof ( MVert ) * bvh->numverts, "bvh->current_xold" );
+       verts = cloth->verts;
+       mfaces = cloth->mfaces;
        
-       for(i = 0; i < bvh->numverts; i++)
+       // in the moment, return zero if no faces there
+       if(!cloth->numfaces)
+               return NULL;
+       
+       // 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(bvh->current_xold[i].co, verts[i].txold);
+               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)
-               return;
-       
-       if(cloth->numverts!=bvh->numverts)
+       if(!bvhtree)
                return;
        
-       if(cloth->verts)
-       {
-               for(i = 0; i < bvh->numverts; i++)
-               {
-                       VECCOPY(bvh->current_x[i].co, verts[i].tx);
-                       VECCOPY(bvh->current_xold[i].co, verts[i].txold);
-               }
-       }
+       mfaces = cloth->mfaces;
        
-       bvh_update(bvh, moving);
-}
-
-DerivedMesh *CDDM_create_tearing ( ClothModifierData *clmd, DerivedMesh *dm )
-{
-       DerivedMesh *result = NULL;
-       unsigned int i = 0, a = 0, j=0;
-       int numverts = dm->getNumVerts ( dm );
-       int numfaces = dm->getNumFaces ( dm );
-
-       MVert *mvert = CDDM_get_verts ( dm );
-       MFace *mface = CDDM_get_faces ( dm );
-
-       MVert *mvert2;
-       MFace *mface2;
-       EdgeHash *edgehash = NULL;
-       Cloth *cloth = clmd->clothObject;
-       ClothSpring *springs = (ClothSpring *)cloth->springs;
-       unsigned int numsprings = cloth->numsprings;
-
-       // create spring tearing hash
-       edgehash = BLI_edgehash_new();
-
-       for ( i = 0; i < numsprings; i++ )
+       // update vertex position in bvh tree
+       if(verts && mfaces)
        {
-               if ( ( springs[i].flags & CLOTH_SPRING_FLAG_DEACTIVATE )
-                                    && ( !BLI_edgehash_haskey ( edgehash, springs[i].ij, springs[i].kl ) ) )
-               {
-                       BLI_edgehash_insert ( edgehash, springs[i].ij, springs[i].kl, NULL );
-                       BLI_edgehash_insert ( edgehash, springs[i].kl, springs[i].ij, NULL );
-                       j++;
-               }
-       }
-
-       // printf("found %d tears\n", j);
-
-       result = CDDM_from_template ( dm, numverts, 0, numfaces );
-
-       if ( !result )
-               return NULL;
-
-       // do verts
-       mvert2 = CDDM_get_verts ( result );
-       for ( a=0; a<numverts; a++ )
-       {
-               MVert *inMV;
-               MVert *mv = &mvert2[a];
-
-               inMV = &mvert[a];
-
-               DM_copy_vert_data ( dm, result, a, a, 1 );
-               *mv = *inMV;
-       }
-
-
-       // do faces
-       mface2 = CDDM_get_faces ( result );
-       for ( a=0, i=0; a<numfaces; a++ )
-       {
-               MFace *mf = &mface2[i];
-               MFace *inMF;
-               inMF = &mface[a];
-
-               /*
-               DM_copy_face_data(dm, result, a, i, 1);
-
-               *mf = *inMF;
-               */
-
-               if ( ( !BLI_edgehash_haskey ( edgehash, mface[a].v1, mface[a].v2 ) )
-                                     && ( !BLI_edgehash_haskey ( edgehash, mface[a].v2, mface[a].v3 ) )
-                                     && ( !BLI_edgehash_haskey ( edgehash, mface[a].v3, mface[a].v4 ) )
-                                     && ( !BLI_edgehash_haskey ( edgehash, mface[a].v4, mface[a].v1 ) ) )
+               for(i = 0; i < cloth->numfaces; i++, mfaces++)
                {
-                       mf->v1 = mface[a].v1;
-                       mf->v2 = mface[a].v2;
-                       mf->v3 = mface[a].v3;
-                       mf->v4 = mface[a].v4;
-
-                       test_index_face ( mf, NULL, 0, 4 );
-
-                       i++;
+                       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);
        }
-
-       CDDM_lower_num_faces ( result, i );
-       CDDM_calc_edges ( result );
-       CDDM_calc_normals ( result );
-
-       BLI_edgehash_free ( edgehash, NULL );
-
-       return result;
 }
 
-int modifiers_indexInObject(Object *ob, ModifierData *md_seek);
-
-int cloth_read_cache(Object *ob, ClothModifierData *clmd, float framenr)
-{
-       FILE *fp = NULL;
-       int stack_index = -1;
-       unsigned int a, ret = 1;
+void bvhselftree_update_from_cloth(ClothModifierData *clmd, int moving)
+{      
+       unsigned int i = 0;
        Cloth *cloth = clmd->clothObject;
+       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;
        
-       stack_index = modifiers_indexInObject(ob, (ModifierData *)clmd);
+       mfaces = cloth->mfaces;
        
-       fp = BKE_ptcache_id_fopen((ID *)ob, 'r', framenr, stack_index);
-       if(!fp)
-               ret = 0;
-       else {
-               for(a = 0; a < cloth->numverts; a++)
+       // update vertex position in bvh tree
+       if(verts && mfaces)
+       {
+               for(i = 0; i < cloth->numverts; i++, verts++)
                {
-                       if(fread(&cloth->verts[a].x, sizeof(float), 3, fp) != 3) 
+                       VECCOPY(&co[0*3], verts->txold);
+                       
+                       // copy new locations into array
+                       if(moving)
                        {
-                               ret = 0;
-                               break;
+                               // update moving positions
+                               VECCOPY(&co_moving[0*3], verts->tx);
+                               
+                               ret = BLI_bvhtree_update_node(bvhtree, i, co, co_moving, 1);
                        }
-                       if(fread(&cloth->verts[a].xconst, sizeof(float), 3, fp) != 3) 
+                       else
                        {
-                               ret = 0;
-                               break;
+                               ret = BLI_bvhtree_update_node(bvhtree, i, co, NULL, 1);
                        }
-                       if(fread(&cloth->verts[a].v, sizeof(float), 3, fp) != 3) 
-                       {
-                               ret = 0;
+                       
+                       // check if tree is already full
+                       if(!ret)
                                break;
-                       }
-               }
-               
-               fclose(fp);
-               
-               if(clmd->sim_parms->lastcachedframe < framenr)
-               {
-                       if(G.rt > 0)
-                               printf("cloth_read_cache problem: lnex - f#: %f, lastCF: %d\n", framenr, clmd->sim_parms->lastcachedframe);
                }
                
-               if(G.rt > 0)
-                       printf("cloth_read_cache: %f successfully \n", framenr);
+               BLI_bvhtree_update_tree(bvhtree);
        }
-       
-       if(G.rt > 0)
-               printf("cloth_read_cache: %f\n", framenr);
-       
-       return ret;
 }
 
 void cloth_clear_cache(Object *ob, ClothModifierData *clmd, float framenr)
 {
-       int stack_index = -1;
+       PTCacheID pid;
        
+       BKE_ptcache_id_from_cloth(&pid, ob, clmd);
+
        // don't do anything as long as we're in editmode!
-       if(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_EDITMODE)
-       {
-               /* delete cache free request */
-               clmd->sim_parms->flags &= ~CLOTH_SIMSETTINGS_FLAG_CCACHE_FFREE;
-               
+       if(pid.cache->edit && ob->mode & OB_MODE_PARTICLE_EDIT)
                return;
-       }
-       
-       /* clear cache if specific frame cleaning requested or cache is not protected */
-       if((!(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_CCACHE_PROTECT)) || (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_CCACHE_FFREE))
-       {
-               stack_index = modifiers_indexInObject(ob, (ModifierData *)clmd);
-               
-               BKE_ptcache_id_clear((ID *)ob, PTCACHE_CLEAR_AFTER, framenr, stack_index);
-               
-               /* update last cached frame # */
-               clmd->sim_parms->lastcachedframe = framenr;
-               
-               /* update first cached frame # */
-               if((framenr < clmd->sim_parms->firstcachedframe) && (clmd->sim_parms->firstcachedframe >=0.0))
-                       clmd->sim_parms->firstcachedframe = -1.0;
-               
-               if(G.rt > 0)
-                       printf("cloth_clear_cache: %f\n", framenr);
-       }
-       
-       /* delete cache free request */
-       clmd->sim_parms->flags &= ~CLOTH_SIMSETTINGS_FLAG_CCACHE_FFREE;
-       
        
+       BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_AFTER, framenr);
 }
-void cloth_write_cache(Object *ob, ClothModifierData *clmd, float framenr)
+
+static int do_init_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *result, int framenr)
 {
-       FILE *fp = NULL;
-       int stack_index = -1;
-       unsigned int a;
-       Cloth *cloth = clmd->clothObject;
-       
-       if(G.rt > 0)
-               printf("cloth_write_cache: %f\n", framenr);
-       
-       if(!cloth)
-       {
-               if(G.rt > 0)
-                       printf("cloth_write_cache: no cloth\n");
-               return;
-       }
+       PointCache *cache;
+
+       cache= clmd->point_cache;
+
+       /* initialize simulation data if it didn't exist already */
+       if(clmd->clothObject == NULL) { 
+               if(!cloth_from_object(ob, clmd, result, framenr, 1)) {
+                       cache->flag &= ~PTCACHE_SIMULATION_VALID;
+                       cache->simframe= 0;
+                       return 0;
+               }
        
-       stack_index = modifiers_indexInObject(ob, (ModifierData *)clmd);
+               if(clmd->clothObject == NULL) {
+                       cache->flag &= ~PTCACHE_SIMULATION_VALID;
+                       cache->simframe= 0;
+                       return 0;
+               }
        
-       fp = BKE_ptcache_id_fopen((ID *)ob, 'w', framenr, stack_index);
-       if(!fp)
-       {
-               if(G.rt > 0)
-                       printf("cloth_write_cache: no fp\n");
-               return;
+               implicit_set_positions(clmd);
        }
-       
-       for(a = 0; a < cloth->numverts; a++)
-       {
-               fwrite(&cloth->verts[a].x, sizeof(float),3,fp);
-               fwrite(&cloth->verts[a].xconst, sizeof(float),3,fp);
-               fwrite(&cloth->verts[a].v, sizeof(float),3,fp);
+
+       return 1;
+}
+
+static int do_step_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *result, int framenr)
+{
+       ClothVertex *verts = NULL;
+       Cloth *cloth;
+       ListBase *effectors = NULL;
+       MVert *mvert;
+       int i, ret = 0;
+
+       /* simulate 1 frame forward */
+       cloth = clmd->clothObject;
+       verts = cloth->verts;
+       mvert = result->getVertArray(result);
+
+       /* force any pinned verts to their constrained location. */
+       for(i = 0; i < clmd->clothObject->numverts; i++, verts++) {
+               /* save the previous position. */
+               VECCOPY(verts->xold, verts->xconst);
+               VECCOPY(verts->txold, verts->x);
+
+               /* Get the current position. */
+               VECCOPY(verts->xconst, mvert[i].co);
+               Mat4MulVecfl(ob->obmat, verts->xconst);
        }
        
-       /* update last cached frame # */
-       clmd->sim_parms->lastcachedframe = MAX2(clmd->sim_parms->lastcachedframe, framenr);
-       
-       /* update first cached frame # */
-       if((clmd->sim_parms->firstcachedframe < 0.0) || ((framenr < clmd->sim_parms->firstcachedframe) && (clmd->sim_parms->firstcachedframe > 0.0)))
-               clmd->sim_parms->firstcachedframe = framenr;
-       
-       if(G.rt > 0)
-               printf("lcf: %d, framenr: %f\n", clmd->sim_parms->lastcachedframe, framenr);
+       tstart();
+
+       /* call the solver. */
+       if(solvers [clmd->sim_parms->solver_type].solver)
+               ret = solvers[clmd->sim_parms->solver_type].solver(ob, framenr, clmd, effectors);
+
+       tend();
 
-       fclose(fp);
+       // printf ( "%f\n", ( float ) tval() );
+       
+       return ret;
 }
 
 /************************************************
  * 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)
 {
-       unsigned int i;
-       Cloth *cloth = clmd->clothObject;
-       float framenr = G.scene->r.cfra;
-       float current_time = bsystem_time ( ob, ( float ) G.scene->r.cfra, 0.0 );
-       ListBase *effectors = NULL;
-       ClothVertex *verts = NULL;
-       float deltaTime = current_time - clmd->sim_parms->sim_time;
-       unsigned int numverts = -1;
-       unsigned int numedges = -1;
-       unsigned int numfaces = -1;
-       MVert *mvert = NULL;
-       MEdge *medge = NULL;
-       MFace *mface = NULL;
-       DerivedMesh *result = NULL;
-       int ret = 0;
-       
-       if(G.rt > 0)
-               printf("clothModifier_do start\n");
-       
-       /* we're getting called two times during file load,
-       resulting in a not valid G.relbase on the first time (cache makes problems)
-       --> just return back */
-       if((clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_LOADED) && (!G.relbase_valid)) 
-       {
-               clmd->sim_parms->flags &= ~CLOTH_SIMSETTINGS_FLAG_LOADED;
-               return dm;
-       }
-       
+       DerivedMesh *result;
+       PointCache *cache;
+       PTCacheID pid;
+       float timescale;
+       int framedelta, framenr, startframe, endframe;
+       int cache_result;
+
+       clmd->scene= scene;     /* nice to pass on later :) */
+       framenr= (int)scene->r.cfra;
+       cache= clmd->point_cache;
        result = CDDM_copy(dm);
-       
-       if(!result)
-       {
+
+       BKE_ptcache_id_from_cloth(&pid, ob, clmd);
+       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;
        }
        
-       numverts = result->getNumVerts(result);
-       numedges = result->getNumEdges(result);
-       numfaces = result->getNumFaces(result);
-       mvert = dm->getVertArray(result);
-       medge = dm->getEdgeArray(result);
-       mface = dm->getFaceArray(result);
-       
-       /* check if cache is active / if file is already saved */
-       /*
-       if ((!G.relbase_valid) && ( deltaTime != 1.0f ))
-       {
-       clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_RESET;
-}
-       */
-       
-       if(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_RESET)
-       {       
-               cloth_free_modifier (ob, clmd);
-               if(G.rt > 0)
-                       printf("clothModifier_do CLOTH_SIMSETTINGS_FLAG_RESET\n");
-       }
-       
-       // unused in the moment, calculated seperately in implicit.c
-       clmd->sim_parms->dt = 1.0f / clmd->sim_parms->stepsPerFrame;
-       
-       if ( ( clmd->clothObject == NULL ) || (clmd->clothObject && (numverts != clmd->clothObject->numverts )) )
-       {       
-               /* only force free the cache if we have a different number of verts */
-               if(clmd->clothObject && (numverts != clmd->clothObject->numverts ))
-               {
-                       if(G.rt > 0)
-                               printf("Force Freeing: numverts != clmd->clothObject->numverts\n");
-                       
-                       clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_CCACHE_FFREE;
-                       cloth_free_modifier ( ob, clmd );
-               }
-               
-               cloth_clear_cache(ob, clmd, 0);
-                               
-               if ( !cloth_from_object ( ob, clmd, result, framenr ) )
+       /* verify we still have the same number of vertices, if not do nothing.
+        * note that this should only happen if the number of vertices changes
+        * during an animation due to a preceding modifier, this should not
+        * happen because of object changes! */
+       if(clmd->clothObject) {
+               if(result->getNumVerts(result) != clmd->clothObject->numverts) {
+                       cache->flag &= ~PTCACHE_SIMULATION_VALID;
+                       cache->simframe= 0;
+                       cache->last_exact= 0;
                        return result;
-       
-               if ( clmd->clothObject == NULL )
-                       return result;
-       
-               cloth = clmd->clothObject;
-               
-               if(!cloth_read_cache(ob, clmd, framenr))
-               {
-                       /* save first frame in case we have a reseted object 
-                       and we move one frame forward.
-                       In that case we would only start with the SECOND frame
-                       if we don't save the current state before 
-                       TODO PROBLEM: IMHO we can't track external movement from the
-                       first frame in this case! */
-                       /*
-                       if ( deltaTime == 1.0f )
-                       cloth_write_cache(ob, clmd, framenr-1.0);
-                       */
-                       if(G.rt > 0)
-                               printf("cloth_from_object NO cloth_read_cache cloth_write_cache\n");
                }
-               else
-               {
-                       if(G.rt > 0)
-                               printf("cloth_from_object cloth_read_cache\n");
-                       
-                       implicit_set_positions(clmd);
-               }
-               
-               clmd->sim_parms->sim_time = current_time;
        }
        
-       // only be active during a specific period:
-       // that's "first frame" and "last frame" on GUI
-       if ( current_time < clmd->sim_parms->firstframe )
-       {
-               if(G.rt > 0)
-                       printf("current_time < clmd->sim_parms->firstframe\n");
+       // unused in the moment, calculated seperately in implicit.c
+       clmd->sim_parms->dt = clmd->sim_parms->timescale / clmd->sim_parms->stepsPerFrame;
+
+       /* handle continuous simulation with the play button */
+       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))
+                       return result;
+
+               do_step_cloth(ob, clmd, result, framenr);
+               cloth_to_object(ob, clmd, result);
+
                return result;
        }
-       else if ( current_time > clmd->sim_parms->lastframe )
-       {
-               int stack_index = modifiers_indexInObject(ob, (ModifierData *)clmd);
-                       
-               if(G.rt > 0)
-                       printf("current_time > clmd->sim_parms->lastframe\n");
-               
-               if(BKE_ptcache_id_exist((ID *)ob, clmd->sim_parms->lastcachedframe, stack_index))
-               {
-                       if(cloth_read_cache(ob, clmd, clmd->sim_parms->lastcachedframe))
-                       {
-                               implicit_set_positions(clmd);
-                               
-                               // Copy the result back to the object.
-                               cloth_to_object (ob, clmd, result);
-                       }
-               }
+
+       /* simulation is only active during a specific period */
+       if(framenr < startframe) {
+               cache->flag &= ~PTCACHE_SIMULATION_VALID;
+               cache->simframe= 0;
+               cache->last_exact= 0;
                return result;
        }
-       
-       // check for autoprotection, but only if cache active
-       if((framenr >= clmd->sim_parms->autoprotect) && (G.relbase_valid))
-       {
-               if(G.rt > 0)
-                       printf("fr#: %f, auto: %d\n", framenr, clmd->sim_parms->autoprotect);
-               clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_CCACHE_PROTECT;
+       else if(framenr > endframe) {
+               framenr= endframe;
        }
-       if(G.rt > 0)
-               printf("clothModifier_do deltaTime=1 cachewrite\n");
-       
-       /* nice moving one frame forward */
-       if ( deltaTime == 1.0f )
-       {
-               clmd->sim_parms->sim_time = current_time;
-               
-               if(G.rt > 0)
-                       printf("clothModifier_do deltaTime=1\n");
-               
-               if(!cloth_read_cache(ob, clmd, framenr))
-               {
-                       verts = cloth->verts;
 
-                       // Force any pinned verts to their constrained location.
-                       for ( i = 0; i < clmd->clothObject->numverts; i++, verts++ )
-                       {
-                               // Save the previous position.
-                               VECCOPY ( verts->xold, verts->xconst );
-                               VECCOPY ( verts->txold, verts->x );
+       if(cache->flag & PTCACHE_SIMULATION_VALID)
+               framedelta= framenr - cache->simframe;
+       else
+               framedelta= -1;
 
-                               // Get the current position.
-                               VECCOPY ( verts->xconst, mvert[i].co );
-                               Mat4MulVecfl ( ob->obmat, verts->xconst );
-                       }
-                       
-                       tstart();
+       /* initialize simulation data if it didn't exist already */
+       if(!do_init_cloth(ob, clmd, result, framenr))
+               return result;
 
-                       // Call the solver.
-                       if ( solvers [clmd->sim_parms->solver_type].solver )
-                       {
-                               ret = solvers [clmd->sim_parms->solver_type].solver ( ob, framenr, clmd, effectors );
-                       }
+       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;
+       }
 
-                       tend();
-                       // printf ( "Cloth simulation time: %f\n", ( float ) tval() );
-                       
-                       if(ret)
-                               cloth_write_cache(ob, clmd, framenr);
-                       else
-                               clmd->sim_parms->sim_time--;
-               }
-               else
-               {
-                       if(G.rt > 0)
-                               printf("clothModifier_do deltaTime=1 cacheread\n");
-                       implicit_set_positions(clmd);
-               }
-               
-               // Copy the result back to the object.
+       /* 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(deltaTime == 0.0f) 
-       {       
-               if(G.rt > 0)
-                       printf("clothModifier_do deltaTime!=1 clmd->clothObject != NULL\n");
-               if(cloth_read_cache(ob, clmd, framenr))
-               {
-                       cloth_to_object (ob, clmd, result);
-                       implicit_set_positions(clmd);
-               }
-               else /* same cache parts are missing */
-               {
-                       /*
-                       clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_RESET;
-                       */
-                       clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_CCACHE_FFREE;
-                       cloth_clear_cache(ob, clmd, 0);
-                       
-                       cloth_write_cache(ob, clmd, framenr);
-               }
+       else if(cache_result==PTCACHE_READ_OLD) {
+               implicit_set_positions(clmd);
+               cache->flag |= PTCACHE_SIMULATION_VALID;
        }
-       else
-       {       
-               if(G.rt > 0)
-                       printf("clothModifier_do deltaTime!=1 clmd->clothObject != NULL\n");
-               if(cloth_read_cache(ob, clmd, framenr))
-               {
-                       cloth_to_object (ob, clmd, result);
-                       implicit_set_positions(clmd);
-                       clmd->sim_parms->sim_time = current_time;
-               }
-               else
-               {
-                       /* jump to a non-existing frame makes sim reset */
-                       clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_RESET;
-               }
+       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 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);
+
+       clmd->sim_parms->timescale *= framenr - cache->simframe;
+
+       /* do simulation */
+       cache->flag |= PTCACHE_SIMULATION_VALID;
+       cache->simframe= framenr;
+
+       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;
 }
 
@@ -787,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 )
@@ -805,7 +622,6 @@ void cloth_free_modifier ( Object *ob, ClothModifierData *clmd )
                MEM_freeN ( cloth );
                clmd->clothObject = NULL;
        }
-       clmd->sim_parms->flags &= ~CLOTH_SIMSETTINGS_FLAG_RESET;
 }
 
 /* frees all */
@@ -858,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 )
@@ -918,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;
@@ -942,9 +760,7 @@ static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm )
                     (clmd->sim_parms->vgroup_bend>0)))
        {
                for ( i = 0; i < numverts; i++, verts++ )
-               {
-                       verts->mass = 1.0; // standard mass
-                       
+               {       
                        dvert = dm->getVertData ( dm, i, CD_MDEFORMVERT );
                        if ( dvert )
                        {
@@ -993,14 +809,14 @@ static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm )
        }
 }
 
-static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *dm, float framenr)
+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};
-       int cache_there = 0;
        Cloth *cloth = NULL;
+       float maxdist = 0;
 
        // If we have a clothObject, free it. 
        if ( clmd->clothObject != NULL )
@@ -1031,21 +847,6 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d
 
        cloth_from_mesh ( ob, clmd, dm );
 
-       if((clmd->sim_parms->firstcachedframe < 0.0) || ((clmd->sim_parms->firstcachedframe >= 0.0) && (!cloth_read_cache(ob, clmd, clmd->sim_parms->firstcachedframe))))
-       {
-               // no cache there
-               cache_there = 0;
-               if(G.rt > 0)
-                       printf("cache_there = 0\n");
-       }
-       else
-       {
-               // we have a cache
-               cache_there = 1;
-               if(G.rt > 0)
-                       printf("cache_there = 1, fcf: %d\n", clmd->sim_parms->firstcachedframe);
-       }
-       
        // create springs 
        clmd->clothObject->springs = NULL;
        clmd->clothObject->numsprings = -1;
@@ -1056,14 +857,15 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d
        // set initial values
        for ( i = 0; i < dm->getNumVerts(dm); i++, verts++ )
        {
-               if(!cache_there)
+               if(first)
                {
                        VECCOPY ( verts->x, mvert[i].co );
                        Mat4MulVecfl ( ob->obmat, verts->x );
                }
                
                /* no GUI interface yet */
-               verts->mass = clmd->sim_parms->mass = 1.0f;
+               verts->mass = clmd->sim_parms->mass; 
+               verts->impulse_count = 0;
 
                if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL )
                        verts->goal= clmd->sim_parms->defgoal;
@@ -1074,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;
@@ -1083,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 );
@@ -1102,18 +904,25 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d
        }
        
        // init our solver
-       if ( solvers [clmd->sim_parms->solver_type].init )
+       if ( solvers [clmd->sim_parms->solver_type].init ) {
                solvers [clmd->sim_parms->solver_type].init ( ob, clmd );
+       }
        
-       if(cache_there)
+       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 );
@@ -1170,6 +979,9 @@ int cloth_add_spring ( ClothModifierData *clmd, unsigned int indexA, unsigned in
                
                spring = ( ClothSpring * ) MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" );
                
+               if(!spring)
+                       return 0;
+               
                spring->ij = indexA;
                spring->kl = indexB;
                spring->restlen =  restlength;
@@ -1186,18 +998,51 @@ int cloth_add_spring ( ClothModifierData *clmd, unsigned int indexA, unsigned in
        return 0;
 }
 
-int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
+static void cloth_free_errorsprings(Cloth *cloth, EdgeHash *edgehash, LinkNode **edgelist)
+{
+       unsigned int i = 0;
+       
+       if ( cloth->springs != NULL )
+       {
+               LinkNode *search = cloth->springs;
+               while(search)
+               {
+                       ClothSpring *spring = search->link;
+                                               
+                       MEM_freeN ( spring );
+                       search = search->next;
+               }
+               BLI_linklist_free(cloth->springs, NULL);
+               
+               cloth->springs = NULL;
+       }
+       
+       if(edgelist)
+       {
+               for ( i = 0; i < cloth->numverts; i++ )
+               {
+                       BLI_linklist_free ( edgelist[i],NULL );
+               }
+
+               MEM_freeN ( edgelist );
+       }
+       
+       if(cloth->edgehash)
+               BLI_edgehash_free ( cloth->edgehash, NULL );
+}
+
+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;
@@ -1210,6 +1055,10 @@ int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
        cloth->springs = NULL;
 
        edgelist = MEM_callocN ( sizeof ( LinkNode * ) * numverts, "cloth_edgelist_alloc" );
+       
+       if(!edgelist)
+               return 0;
+       
        for ( i = 0; i < numverts; i++ )
        {
                edgelist[i] = NULL;
@@ -1244,9 +1093,15 @@ int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
                        
                        BLI_linklist_prepend ( &cloth->springs, spring );
                }
+               else
+               {
+                       cloth_free_errorsprings(cloth, edgehash, edgelist);
+                       return 0;
+               }
        }
        
-       clmd->sim_parms->avg_spring_len /= struct_springs;
+       if(struct_springs > 0)
+               clmd->sim_parms->avg_spring_len /= struct_springs;
        
        for(i = 0; i < numverts; i++)
        {
@@ -1256,7 +1111,17 @@ int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
        // shear springs
        for ( i = 0; i < numfaces; i++ )
        {
+               // triangle faces already have shear springs due to structural geometry
+               if ( !mface[i].v4 )
+                       continue; 
+               
                spring = ( ClothSpring *) MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" );
+               
+               if(!spring)
+               {
+                       cloth_free_errorsprings(cloth, edgehash, edgelist);
+                       return 0;
+               }
 
                spring->ij = MIN2(mface[i].v1, mface[i].v3);
                spring->kl = MAX2(mface[i].v3, mface[i].v1);
@@ -1271,23 +1136,28 @@ int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
 
                BLI_linklist_prepend ( &cloth->springs, spring );
 
-               if ( mface[i].v4 )
+               
+               // if ( mface[i].v4 ) --> Quad face
+               spring = ( ClothSpring * ) MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" );
+               
+               if(!spring)
                {
-                       spring = ( ClothSpring * ) MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" );
+                       cloth_free_errorsprings(cloth, edgehash, edgelist);
+                       return 0;
+               }
 
-                       spring->ij = MIN2(mface[i].v2, mface[i].v4);
-                       spring->kl = MAX2(mface[i].v4, mface[i].v2);
-                       VECSUB ( temp, cloth->verts[spring->kl].x, cloth->verts[spring->ij].x );
-                       spring->restlen =  sqrt ( INPR ( temp, temp ) );
-                       spring->type = CLOTH_SPRING_TYPE_SHEAR;
-                       spring->stiffness = (cloth->verts[spring->kl].shear_stiff + cloth->verts[spring->ij].shear_stiff) / 2.0;
+               spring->ij = MIN2(mface[i].v2, mface[i].v4);
+               spring->kl = MAX2(mface[i].v4, mface[i].v2);
+               VECSUB ( temp, cloth->verts[spring->kl].x, cloth->verts[spring->ij].x );
+               spring->restlen =  sqrt ( INPR ( temp, temp ) );
+               spring->type = CLOTH_SPRING_TYPE_SHEAR;
+               spring->stiffness = (cloth->verts[spring->kl].shear_stiff + cloth->verts[spring->ij].shear_stiff) / 2.0;
 
-                       BLI_linklist_append ( &edgelist[spring->ij], spring );
-                       BLI_linklist_append ( &edgelist[spring->kl], spring );
-                       shear_springs++;
+               BLI_linklist_append ( &edgelist[spring->ij], spring );
+               BLI_linklist_append ( &edgelist[spring->kl], spring );
+               shear_springs++;
 
-                       BLI_linklist_prepend ( &cloth->springs, spring );
-               }
+               BLI_linklist_prepend ( &cloth->springs, spring );
        }
        
        // bending springs
@@ -1306,19 +1176,24 @@ int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
                        
                        // check for existing spring
                        // check also if startpoint is equal to endpoint
-                       if ( !BLI_edgehash_haskey ( edgehash, index2, tspring2->ij )
-                                                  && !BLI_edgehash_haskey ( edgehash, tspring2->ij, index2 )
-                                                  && ( index2!=tspring2->ij ) )
+                       if ( !BLI_edgehash_haskey ( edgehash, MIN2(tspring2->ij, index2), MAX2(tspring2->ij, index2) )
+                       && ( index2!=tspring2->ij ) )
                        {
                                spring = ( ClothSpring * ) MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" );
+                               
+                               if(!spring)
+                               {
+                                       cloth_free_errorsprings(cloth, edgehash, edgelist);
+                                       return 0;
+                               }
 
                                spring->ij = MIN2(tspring2->ij, index2);
                                spring->kl = MAX2(tspring2->ij, index2);
-                               VECSUB ( temp, cloth->verts[index2].x, cloth->verts[tspring2->ij].x );
+                               VECSUB ( temp, cloth->verts[spring->kl].x, cloth->verts[spring->ij].x );
                                spring->restlen =  sqrt ( INPR ( temp, temp ) );
                                spring->type = CLOTH_SPRING_TYPE_BENDING;
                                spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0;
-                               BLI_edgehash_insert ( edgehash, spring->ij, index2, NULL );
+                               BLI_edgehash_insert ( edgehash, spring->ij, spring->kl, NULL );
                                bend_springs++;
 
                                BLI_linklist_prepend ( &cloth->springs, spring );
@@ -1328,14 +1203,32 @@ int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
                search2 = search2->next;
        }
        
-       cloth->numsprings = struct_springs + shear_springs + bend_springs;
+       /* insert other near springs in edgehash AFTER bending springs are calculated (for selfcolls) */
+       for ( i = 0; i < numedges; i++ ) // struct springs
+               BLI_edgehash_insert ( edgehash, MIN2(medge[i].v1, medge[i].v2), MAX2(medge[i].v2, medge[i].v1), NULL );
        
-       for ( i = 0; i < numverts; i++ )
+       for ( i = 0; i < numfaces; i++ ) // edge springs
        {
-               BLI_linklist_free ( edgelist[i],NULL );
+               if(mface[i].v4)
+               {
+                       BLI_edgehash_insert ( edgehash, MIN2(mface[i].v1, mface[i].v3), MAX2(mface[i].v3, mface[i].v1), NULL );
+                       
+                       BLI_edgehash_insert ( edgehash, MIN2(mface[i].v2, mface[i].v4), MAX2(mface[i].v2, mface[i].v4), NULL );
+               }
        }
+       
+       
+       cloth->numsprings = struct_springs + shear_springs + bend_springs;
+       
        if ( edgelist )
+       {
+               for ( i = 0; i < numverts; i++ )
+               {
+                       BLI_linklist_free ( edgelist[i],NULL );
+               }
+       
                MEM_freeN ( edgelist );
+       }
        
        cloth->edgehash = edgehash;