svn merge -r40166:40279 ^/trunk/blender
[blender.git] / source / blender / blenkernel / intern / collision.c
index 5c9cc441b950afa4769a7d9b329931ff3c3262e3..700c6693a248928a7b893b0b20c0370e262f8f46 100644 (file)
@@ -1,31 +1,36 @@
-/*  collision.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*
-* The Original Code is Copyright (C) Blender Foundation
-* All rights reserved.
-*
-* The Original Code is: all of this file.
-*
-* Contributor(s): none yet.
-*
-* ***** END GPL LICENSE BLOCK *****
-*/
+/*
+ * $Id$
+ *
+ * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/collision.c
+ *  \ingroup bke
+ */
+
 
 #include "MEM_guardedalloc.h"
 
 #include "DNA_scene_types.h"
 #include "DNA_meshdata_types.h"
 
+#include "BLI_utildefines.h"
 #include "BLI_blenlib.h"
 #include "BLI_math.h"
 #include "BLI_edgehash.h"
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+#include "BLI_memarena.h"
+#include "BLI_rand.h"
 
 #include "BKE_DerivedMesh.h"
 #include "BKE_global.h"
@@ -49,7 +59,7 @@
 #include "BKE_mesh.h"
 #include "BKE_object.h"
 #include "BKE_modifier.h"
-#include "BKE_utildefines.h"
+
 #include "BKE_DerivedMesh.h"
 #ifdef USE_BULLET
 #include "Bullet-C-Api.h"
 #include "BLI_kdopbvh.h"
 #include "BKE_collision.h"
 
+#ifdef WITH_ELTOPO
+#include "eltopo-capi.h"
+#endif
+
 
 /***********************************
 Collision modifier code start
@@ -83,7 +97,7 @@ BVHTree *bvhtree_build_from_mvert ( MFace *mfaces, unsigned int numfaces, MVert
 {
        BVHTree *tree;
        float co[12];
-       int i;
+       unsigned int i;
        MFace *tface = mfaces;
 
        tree = BLI_bvhtree_new ( numfaces*2, epsilon, 4, 26 );
@@ -91,11 +105,11 @@ BVHTree *bvhtree_build_from_mvert ( MFace *mfaces, unsigned int numfaces, MVert
        // fill tree
        for ( i = 0; i < numfaces; i++, tface++ )
        {
-               VECCOPY ( &co[0*3], x[tface->v1].co );
-               VECCOPY ( &co[1*3], x[tface->v2].co );
-               VECCOPY ( &co[2*3], x[tface->v3].co );
+               copy_v3_v3 ( &co[0*3], x[tface->v1].co );
+               copy_v3_v3 ( &co[1*3], x[tface->v2].co );
+               copy_v3_v3 ( &co[2*3], x[tface->v3].co );
                if ( tface->v4 )
-                       VECCOPY ( &co[3*3], x[tface->v4].co );
+                       copy_v3_v3 ( &co[3*3], x[tface->v4].co );
 
                BLI_bvhtree_insert ( tree, i, co, ( mfaces->v4 ? 4 : 3 ) );
        }
@@ -120,21 +134,21 @@ void bvhtree_update_from_mvert ( BVHTree * bvhtree, MFace *faces, int numfaces,
        {
                for ( i = 0; i < numfaces; i++, mfaces++ )
                {
-                       VECCOPY ( &co[0*3], x[mfaces->v1].co );
-                       VECCOPY ( &co[1*3], x[mfaces->v2].co );
-                       VECCOPY ( &co[2*3], x[mfaces->v3].co );
+                       copy_v3_v3 ( &co[0*3], x[mfaces->v1].co );
+                       copy_v3_v3 ( &co[1*3], x[mfaces->v2].co );
+                       copy_v3_v3 ( &co[2*3], x[mfaces->v3].co );
                        if ( mfaces->v4 )
-                               VECCOPY ( &co[3*3], x[mfaces->v4].co );
+                               copy_v3_v3 ( &co[3*3], x[mfaces->v4].co );
 
                        // copy new locations into array
                        if ( moving && xnew )
                        {
                                // update moving positions
-                               VECCOPY ( &co_moving[0*3], xnew[mfaces->v1].co );
-                               VECCOPY ( &co_moving[1*3], xnew[mfaces->v2].co );
-                               VECCOPY ( &co_moving[2*3], xnew[mfaces->v3].co );
+                               copy_v3_v3 ( &co_moving[0*3], xnew[mfaces->v1].co );
+                               copy_v3_v3 ( &co_moving[1*3], xnew[mfaces->v2].co );
+                               copy_v3_v3 ( &co_moving[2*3], xnew[mfaces->v3].co );
                                if ( mfaces->v4 )
-                                       VECCOPY ( &co_moving[3*3], xnew[mfaces->v4].co );
+                                       copy_v3_v3 ( &co_moving[3*3], xnew[mfaces->v4].co );
 
                                ret = BLI_bvhtree_update_node ( bvhtree, i, co, co_moving, ( mfaces->v4 ? 4 : 3 ) );
                        }
@@ -163,8 +177,8 @@ Collision modifier code end
 */
 
 #define mySWAP(a,b) do { double tmp = b ; b = a ; a = tmp ; } while(0)
-
-int 
+#if 0 /* UNUSED */
+static int 
 gsl_poly_solve_cubic (double a, double b, double c, 
                                          double *x0, double *x1, double *x2)
 {
@@ -254,7 +268,7 @@ gsl_poly_solve_cubic (double a, double b, double c,
 *
 * copied from GSL
 */
-int 
+static int 
 gsl_poly_solve_quadratic (double a, double b, double c, 
                                                  double *x0, double *x1)
 {
@@ -312,7 +326,7 @@ gsl_poly_solve_quadratic (double a, double b, double c,
                return 0;
        }
 }
-
+#endif /* UNUSED */
 
 
 
@@ -480,8 +494,8 @@ DO_INLINE void collision_interpolateOnTriangle ( float to[3], float v1[3], float
        VECADDMUL ( to, v3, w3 );
 }
 
-
-int cloth_collision_response_static ( ClothModifierData *clmd, CollisionModifierData *collmd, CollPair *collpair, CollPair *collision_end )
+#ifndef WITH_ELTOPO
+static int cloth_collision_response_static ( ClothModifierData *clmd, CollisionModifierData *collmd, CollPair *collpair, CollPair *collision_end )
 {
        int result = 0;
        Cloth *cloth1;
@@ -537,7 +551,7 @@ int cloth_collision_response_static ( ClothModifierData *clmd, CollisionModifier
                        float temp[3], spf;
 
                        // calculate tangential velocity
-                       VECCOPY ( temp, collpair->normal );
+                       copy_v3_v3 ( temp, collpair->normal );
                        mul_v3_fl( temp, magrelVel );
                        VECSUB ( vrel_t_pre, relativeVelocity, temp );
 
@@ -595,12 +609,799 @@ int cloth_collision_response_static ( ClothModifierData *clmd, CollisionModifier
        }
        return result;
 }
+#endif /* !WITH_ELTOPO */
+
+#ifdef WITH_ELTOPO
+typedef struct edgepairkey {
+       int a1, a2, b1, b2;
+} edgepairkey;
+
+unsigned int edgepair_hash(void *vkey)
+{
+       edgepairkey *key = vkey;
+       int keys[4] = {key->a1, key->a2, key->b1, key->b2};
+       int i, j;
+       
+       for (i=0; i<4; i++) {
+               for (j=0; j<3; j++) {
+                       if (keys[j] >= keys[j+1]) {
+                               SWAP(int, keys[j], keys[j+1]);
+                       }
+               }
+       }
+       
+       return keys[0]*101 + keys[1]*72 + keys[2]*53 + keys[3]*34;
+}
+
+int edgepair_cmp(const void *va, const void *vb)
+{
+       edgepairkey *a = va, *b = vb;
+       int keysa[4] = {a->a1, a->a2, a->b1, a->b2};
+       int keysb[4] = {b->a1, b->a2, b->b1, b->b2};
+       int i;
+       
+       for (i=0; i<4; i++) {
+               int j, ok=0;
+               for (j=0; j<4; j++) {
+                       if (keysa[i] == keysa[j]) {
+                               ok = 1;
+                               break;
+                       }
+               }
+               if (!ok)
+                       return -1;
+       }
+       
+       return 0;
+}
+
+static void get_edgepairkey(edgepairkey *key, int a1, int a2, int b1, int b2)
+{
+       key->a1 = a1;
+       key->a2 = a2;
+       key->b1 = b1;
+       key->b2 = b2;
+}
+
+/*an immense amount of duplication goes on here. . .a major performance hit, I'm sure*/
+static CollPair* cloth_edge_collision ( ModifierData *md1, ModifierData *md2, 
+                                                                               BVHTreeOverlap *overlap, CollPair *collpair,
+                                                                               GHash *visithash, MemArena *arena)
+{
+       ClothModifierData *clmd = ( ClothModifierData * ) md1;
+       CollisionModifierData *collmd = ( CollisionModifierData * ) md2;
+       MFace *face1=NULL, *face2 = NULL;
+       ClothVertex *verts1 = clmd->clothObject->verts;
+       double distance = 0;
+       edgepairkey *key, tstkey;
+       float epsilon1 = clmd->coll_parms->epsilon;
+       float epsilon2 = BLI_bvhtree_getepsilon ( collmd->bvhtree );
+       float no[3], uv[3], t, relnor;
+       int i, i1, i2, i3, i4, i5, i6;
+       Cloth *cloth = clmd->clothObject;
+       float n1[3], n2[3], off[3], v1[2][3], v2[2][3], v3[2][3], v4[2][3], v5[2][3], v6[2][3];
+       void **verts[] = {v1, v2, v3, v4, v5, v6};
+       int j, ret, bp1, bp2, bp3, ap1, ap2, ap3, table[6];
+       
+       face1 = & ( clmd->clothObject->mfaces[overlap->indexA] );
+       face2 = & ( collmd->mfaces[overlap->indexB] );
+
+       // check all 4 possible collisions
+       for ( i = 0; i < 4; i++ )
+       {
+               if ( i == 0 )
+               {
+                       // fill faceA
+                       ap1 = face1->v1;
+                       ap2 = face1->v2;
+                       ap3 = face1->v3;
+
+                       // fill faceB
+                       bp1 = face2->v1;
+                       bp2 = face2->v2;
+                       bp3 = face2->v3;
+               }
+               else if ( i == 1 )
+               {
+                       if ( face1->v4 )
+                       {
+                               // fill faceA
+                               ap1 = face1->v1;
+                               ap2 = face1->v3;
+                               ap3 = face1->v4;
+
+                               // fill faceB
+                               bp1 = face2->v1;
+                               bp2 = face2->v2;
+                               bp3 = face2->v3;
+                       }
+                       else {
+                               continue;
+                       }
+               }
+               if ( i == 2 )
+               {
+                       if ( face2->v4 )
+                       {
+                               // fill faceA
+                               ap1 = face1->v1;
+                               ap2 = face1->v2;
+                               ap3 = face1->v3;
+
+                               // fill faceB
+                               bp1 = face2->v1;
+                               bp2 = face2->v3;
+                               bp3 = face2->v4;
+                       }
+                       else {
+                               continue;
+                       }
+               }
+               else if ( i == 3 )
+               {
+                       if ( face1->v4 && face2->v4 )
+                       {
+                               // fill faceA
+                               ap1 = face1->v1;
+                               ap2 = face1->v3;
+                               ap3 = face1->v4;
+
+                               // fill faceB
+                               bp1 = face2->v1;
+                               bp2 = face2->v3;
+                               bp3 = face2->v4;
+                       }
+                       else {
+                               continue;
+                       }
+               }
+               
+               copy_v3_v3(v1[0], cloth->verts[ap1].txold); 
+               copy_v3_v3(v1[1], cloth->verts[ap1].tx);
+               copy_v3_v3(v2[0], cloth->verts[ap2].txold);
+               copy_v3_v3(v2[1], cloth->verts[ap2].tx);
+               copy_v3_v3(v3[0], cloth->verts[ap3].txold);
+               copy_v3_v3(v3[1], cloth->verts[ap3].tx);
+               
+               copy_v3_v3(v4[0], collmd->current_x[bp1].co);
+               copy_v3_v3(v4[1], collmd->current_xnew[bp1].co);
+               copy_v3_v3(v5[0], collmd->current_x[bp2].co);
+               copy_v3_v3(v5[1], collmd->current_xnew[bp2].co);
+               copy_v3_v3(v6[0], collmd->current_x[bp3].co);
+               copy_v3_v3(v6[1], collmd->current_xnew[bp3].co);
+               
+               normal_tri_v3(n2, v4[1], v5[1], v6[1]);
+
+               /*offset new positions a bit, to account for margins*/
+               i1 = ap1; i2 = ap2; i3 = ap3;
+               i4 = bp1; i5 = bp2; i6 = bp3;
+
+               for (j=0; j<3; j++) {
+                       int collp1, collp2, k, j2 = (j+1)%3;
+                       
+                       table[0] = ap1; table[1] = ap2; table[2] = ap3;
+                       table[3] = bp1; table[4] = bp2; table[5] = bp3;
+                       for (k=0; k<3; k++) {
+                               float p1[3], p2[3];
+                               int k2 = (k+1)%3;
+                               
+                               get_edgepairkey(&tstkey, table[j], table[j2], table[k+3], table[k2+3]);
+                               //if (BLI_ghash_haskey(visithash, &tstkey))
+                               //      continue;
+                               
+                               key = BLI_memarena_alloc(arena, sizeof(edgepairkey));
+                               *key = tstkey;
+                               BLI_ghash_insert(visithash, key, NULL);
+
+                               sub_v3_v3v3(p1, verts[j], verts[j2]);
+                               sub_v3_v3v3(p2, verts[k+3], verts[k2+3]);
+                               
+                               cross_v3_v3v3(off, p1, p2);
+                               normalize_v3(off);
+
+                               if (dot_v3v3(n2, off) < 0.0)
+                                       negate_v3(off);
+                               
+                               mul_v3_fl(off,  epsilon1 + epsilon2 + ALMOST_ZERO);
+                               copy_v3_v3(p1, verts[k+3]);
+                               copy_v3_v3(p2, verts[k2+3]);
+                               add_v3_v3(p1, off);
+                               add_v3_v3(p2, off);
+                               
+                               ret = eltopo_line_line_moving_isect_v3v3_f(verts[j], table[j], verts[j2], table[j2], 
+                                                                                                                  p1, table[k+3], p2, table[k2+3], 
+                                                                                                                  no, uv, &t, &relnor);
+                               /*cloth vert versus coll face*/
+                               if (ret) {
+                                       collpair->ap1 = table[j]; collpair->ap2 = table[j2]; 
+                                       collpair->bp1 = table[k+3]; collpair->bp2 = table[k2+3];
+                                       
+                                       /*I'm not sure if this is correct, but hopefully it's 
+                                         better then simply ignoring back edges*/
+                                       if (dot_v3v3(n2, no) < 0.0) {
+                                               negate_v3(no);
+                                       }
+                                       
+                                       copy_v3_v3(collpair->normal, no);
+                                       mul_v3_v3fl(collpair->vector, collpair->normal, relnor);
+                                       collpair->distance = relnor;
+                                       collpair->time = t;
+                                       
+                                       copy_v2_v2(collpair->bary, uv);
+                                       
+                                       collpair->flag = COLLISION_IS_EDGES;
+                                       collpair++;
+                               }
+                       }
+               }
+       }
+       
+       return collpair;
+}
+
+static int cloth_edge_collision_response_moving ( ClothModifierData *clmd, CollisionModifierData *collmd, CollPair *collpair, CollPair *collision_end )
+{
+       int result = 0;
+       Cloth *cloth1;
+       float w1, w2;
+       float v1[3], v2[3], relativeVelocity[3];
+       float magrelVel, pimpulse[3];
+
+       cloth1 = clmd->clothObject;
+
+       for ( ; collpair != collision_end; collpair++ )
+       {
+               if (!(collpair->flag & COLLISION_IS_EDGES))
+                       continue;
+               
+               // was: txold
+               w1 = collpair->bary[0]; w2 = collpair->bary[1];                 
+               
+               // Calculate relative "velocity".
+               VECADDFAC(v1, cloth1->verts[collpair->ap1].tv, cloth1->verts[collpair->ap2].tv, w1);
+               VECADDFAC(v2, collmd->current_v[collpair->bp1].co, collmd->current_v[collpair->bp2].co, w2);
+               
+               VECSUB ( relativeVelocity, v2, v1);
+               
+               // Calculate the normal component of the relative velocity (actually only the magnitude - the direction is stored in 'normal').
+               magrelVel = INPR ( relativeVelocity, collpair->normal );
+
+               // If v_n_mag < 0 the edges are approaching each other.
+               if ( magrelVel > ALMOST_ZERO )
+               {
+                       // Calculate Impulse magnitude to stop all motion in normal direction.
+                       float magtangent = 0, repulse = 0, d = 0;
+                       double impulse = 0.0;
+                       float vrel_t_pre[3];
+                       float temp[3], spf;
+                       
+                       zero_v3(pimpulse);
+                       
+                       // calculate tangential velocity
+                       VECCOPY ( temp, collpair->normal );
+                       mul_v3_fl( temp, magrelVel );
+                       VECSUB ( vrel_t_pre, relativeVelocity, temp );
+
+                       // Decrease in magnitude of relative tangential velocity due to coulomb friction
+                       // in original formula "magrelVel" should be the "change of relative velocity in normal direction"
+                       magtangent = MIN2 ( clmd->coll_parms->friction * 0.01 * magrelVel,sqrt ( INPR ( vrel_t_pre,vrel_t_pre ) ) );
+
+                       // Apply friction impulse.
+                       if ( magtangent > ALMOST_ZERO )
+                       {
+                               normalize_v3( vrel_t_pre );
+
+                               impulse = magtangent; 
+                               VECADDMUL ( pimpulse, vrel_t_pre, impulse);
+                       }
+
+                       // Apply velocity stopping impulse
+                       // I_c = m * v_N / 2.0
+                       // no 2.0 * magrelVel normally, but looks nicer DG
+                       impulse =  magrelVel;
+                       
+                       mul_v3_fl(collpair->normal, 0.5);
+                       VECADDMUL ( pimpulse, collpair->normal, impulse);
+
+                       // Apply repulse impulse if distance too short
+                       // I_r = -min(dt*kd, m(0,1d/dt - v_n))
+                       spf = (float)clmd->sim_parms->stepsPerFrame / clmd->sim_parms->timescale;
+
+                       d = collpair->distance;
+                       if ( ( magrelVel < 0.1*d*spf && ( d > ALMOST_ZERO ) ) )
+                       {
+                               repulse = MIN2 ( d*1.0/spf, 0.1*d*spf - magrelVel );
+
+                               // stay on the safe side and clamp repulse
+                               if ( impulse > ALMOST_ZERO )
+                                       repulse = MIN2 ( repulse, 5.0*impulse );
+                               repulse = MAX2 ( impulse, repulse );
+
+                               impulse = repulse / ( 5.0 ); // original 2.0 / 0.25
+                               VECADDMUL ( pimpulse, collpair->normal, impulse);
+                       }
+                       
+                       w2 = 1.0f-w1;
+                       if (w1 < 0.5)
+                               w1 *= 2.0;
+                       else
+                               w2 *= 2.0;
+                       
+                       VECADDFAC(cloth1->verts[collpair->ap1].impulse, cloth1->verts[collpair->ap1].impulse, pimpulse, w1*2.0);
+                       VECADDFAC(cloth1->verts[collpair->ap2].impulse, cloth1->verts[collpair->ap2].impulse, pimpulse, w2*2.0);
+                       
+                       cloth1->verts[collpair->ap1].impulse_count++;
+                       cloth1->verts[collpair->ap2].impulse_count++;
+                       
+                       result = 1;
+               }
+       } 
+       
+       return result;
+}
+
+static int cloth_collision_response_moving ( ClothModifierData *clmd, CollisionModifierData *collmd, CollPair *collpair, CollPair *collision_end )
+{
+       int result = 0;
+       Cloth *cloth1;
+       float w1, w2, w3, u1, u2, u3;
+       float v1[3], v2[3], relativeVelocity[3];
+       float magrelVel;
+       float epsilon2 = BLI_bvhtree_getepsilon ( collmd->bvhtree );
+       
+       cloth1 = clmd->clothObject;
+
+       for ( ; collpair != collision_end; collpair++ )
+       {
+               if (collpair->flag & COLLISION_IS_EDGES)
+                       continue;
+               
+               if ( collpair->flag & COLLISION_USE_COLLFACE ) {
+                       // was: txold
+                       w1 = collpair->bary[0]; w2 = collpair->bary[1]; w3 = collpair->bary[2];                 
+
+                       // Calculate relative "velocity".
+                       collision_interpolateOnTriangle ( v1, collmd->current_v[collpair->bp1].co, collmd->current_v[collpair->bp2].co, collmd->current_v[collpair->bp3].co, w1, w2, w3);
+                       
+                       VECSUB ( relativeVelocity, v1, cloth1->verts[collpair->collp].tv);
+                       
+                       // Calculate the normal component of the relative velocity (actually only the magnitude - the direction is stored in 'normal').
+                       magrelVel = INPR ( relativeVelocity, collpair->normal );
+       
+                       // If v_n_mag < 0 the edges are approaching each other.
+                       if ( magrelVel > ALMOST_ZERO )
+                       {
+                               // Calculate Impulse magnitude to stop all motion in normal direction.
+                               float magtangent = 0, repulse = 0, d = 0;
+                               double impulse = 0.0;
+                               float vrel_t_pre[3];
+                               float temp[3], spf;
+       
+                               // calculate tangential velocity
+                               VECCOPY ( temp, collpair->normal );
+                               mul_v3_fl( temp, magrelVel );
+                               VECSUB ( vrel_t_pre, relativeVelocity, temp );
+       
+                               // Decrease in magnitude of relative tangential velocity due to coulomb friction
+                               // in original formula "magrelVel" should be the "change of relative velocity in normal direction"
+                               magtangent = MIN2 ( clmd->coll_parms->friction * 0.01 * magrelVel,sqrt ( INPR ( vrel_t_pre,vrel_t_pre ) ) );
+       
+                               // Apply friction impulse.
+                               if ( magtangent > ALMOST_ZERO )
+                               {
+                                       normalize_v3( vrel_t_pre );
+       
+                                       impulse = magtangent; // 2.0 * 
+                                       VECADDMUL ( cloth1->verts[collpair->collp].impulse, vrel_t_pre, impulse);
+                               }
+       
+                               // Apply velocity stopping impulse
+                               // I_c = m * v_N / 2.0
+                               // no 2.0 * magrelVel normally, but looks nicer DG
+                               impulse =  magrelVel/2.0;
+       
+                               VECADDMUL ( cloth1->verts[collpair->collp].impulse, collpair->normal, impulse);
+                               cloth1->verts[collpair->collp].impulse_count++;
+       
+                               // Apply repulse impulse if distance too short
+                               // I_r = -min(dt*kd, m(0,1d/dt - v_n))
+                               spf = (float)clmd->sim_parms->stepsPerFrame / clmd->sim_parms->timescale;
+       
+                               d = -collpair->distance;
+                               if ( ( magrelVel < 0.1*d*spf ) && ( d > ALMOST_ZERO ) )
+                               {
+                                       repulse = MIN2 ( d*1.0/spf, 0.1*d*spf - magrelVel );
+       
+                                       // stay on the safe side and clamp repulse
+                                       if ( impulse > ALMOST_ZERO )
+                                               repulse = MIN2 ( repulse, 5.0*impulse );
+                                       repulse = MAX2 ( impulse, repulse );
+       
+                                       impulse = repulse / ( 5.0 ); // original 2.0 / 0.25
+                                       VECADDMUL ( cloth1->verts[collpair->collp].impulse, collpair->normal, impulse);
+                               }
+       
+                               result = 1;
+                       }
+               } else {        
+                       w1 = collpair->bary[0]; w2 = collpair->bary[1]; w3 = collpair->bary[2];                 
+
+                       // Calculate relative "velocity".
+                       collision_interpolateOnTriangle ( v1, cloth1->verts[collpair->ap1].tv, cloth1->verts[collpair->ap2].tv, cloth1->verts[collpair->ap3].tv, w1, w2, w3 );
+       
+                       VECSUB ( relativeVelocity, collmd->current_v[collpair->collp].co, v1);
+                       
+                       // Calculate the normal component of the relative velocity (actually only the magnitude - the direction is stored in 'normal').
+                       magrelVel = INPR ( relativeVelocity, collpair->normal );
+       
+                       // If v_n_mag < 0 the edges are approaching each other.
+                       if ( magrelVel > ALMOST_ZERO )
+                       {
+                               // Calculate Impulse magnitude to stop all motion in normal direction.
+                               float magtangent = 0, repulse = 0, d = 0;
+                               double impulse = 0.0;
+                               float vrel_t_pre[3], pimpulse[3] = {0.0f, 0.0f, 0.0f};
+                               float temp[3], spf;
+       
+                               // calculate tangential velocity
+                               VECCOPY ( temp, collpair->normal );
+                               mul_v3_fl( temp, magrelVel );
+                               VECSUB ( vrel_t_pre, relativeVelocity, temp );
+       
+                               // Decrease in magnitude of relative tangential velocity due to coulomb friction
+                               // in original formula "magrelVel" should be the "change of relative velocity in normal direction"
+                               magtangent = MIN2 ( clmd->coll_parms->friction * 0.01 * magrelVel,sqrt ( INPR ( vrel_t_pre,vrel_t_pre ) ) );
+       
+                               // Apply friction impulse.
+                               if ( magtangent > ALMOST_ZERO )
+                               {
+                                       normalize_v3( vrel_t_pre );
+       
+                                       impulse = magtangent; // 2.0 * 
+                                       VECADDMUL ( pimpulse, vrel_t_pre, impulse);
+                               }
+       
+                               // Apply velocity stopping impulse
+                               // I_c = m * v_N / 2.0
+                               // no 2.0 * magrelVel normally, but looks nicer DG
+                               impulse =  magrelVel/2.0;
+       
+                               VECADDMUL ( pimpulse, collpair->normal, impulse);
+       
+                               // Apply repulse impulse if distance too short
+                               // I_r = -min(dt*kd, m(0,1d/dt - v_n))
+                               spf = (float)clmd->sim_parms->stepsPerFrame / clmd->sim_parms->timescale;
+       
+                               d = -collpair->distance;
+                               if ( ( magrelVel < 0.1*d*spf ) && ( d > ALMOST_ZERO ) )
+                               {
+                                       repulse = MIN2 ( d*1.0/spf, 0.1*d*spf - magrelVel );
+       
+                                       // stay on the safe side and clamp repulse
+                                       if ( impulse > ALMOST_ZERO )
+                                               repulse = MIN2 ( repulse, 5.0*impulse );
+                                       repulse = MAX2 ( impulse, repulse );
+       
+                                       impulse = repulse / ( 2.0 ); // original 2.0 / 0.25
+                                       VECADDMUL ( pimpulse, collpair->normal, impulse);
+                               }
+                               
+                               if (w1 < 0.5) w1 *= 2.0;
+                               if (w2 < 0.5) w2 *= 2.0;
+                               if (w3 < 0.5) w3 *= 2.0;
+                               
+                               VECADDMUL(cloth1->verts[collpair->ap1].impulse, pimpulse, w1*2.0);
+                               VECADDMUL(cloth1->verts[collpair->ap2].impulse, pimpulse, w2*2.0);
+                               VECADDMUL(cloth1->verts[collpair->ap3].impulse, pimpulse, w3*2.0);
+                               cloth1->verts[collpair->ap1].impulse_count++;
+                               cloth1->verts[collpair->ap2].impulse_count++;
+                               cloth1->verts[collpair->ap3].impulse_count++;
+                               
+                               result = 1;
+                       }
+               }
+       } 
+       
+       return result;
+}
+
+
+typedef struct tripairkey {
+       int p, a1, a2, a3;
+} tripairkey;
+
+unsigned int tripair_hash(void *vkey)
+{
+       tripairkey *key = vkey;
+       int keys[4] = {key->p, key->a1, key->a2, key->a3};
+       int i, j;
+       
+       for (i=0; i<4; i++) {
+               for (j=0; j<3; j++) {
+                       if (keys[j] >= keys[j+1]) {
+                               SWAP(int, keys[j], keys[j+1]);
+                       }
+               }
+       }
+       
+       return keys[0]*101 + keys[1]*72 + keys[2]*53 + keys[3]*34;
+}
+
+int tripair_cmp(const void *va, const void *vb)
+{
+       tripairkey *a = va, *b = vb;
+       int keysa[4] = {a->p, a->a1, a->a2, a->a3};
+       int keysb[4] = {b->p, b->a1, b->a2, b->a3};
+       int i;
+       
+       for (i=0; i<4; i++) {
+               int j, ok=0;
+               for (j=0; j<4; j++) {
+                       if (keysa[i] == keysa[j]) {
+                               ok = 1;
+                               break;
+                       }
+               }
+               if (!ok)
+                       return -1;
+       }
+       
+       return 0;
+}
+
+static void get_tripairkey(tripairkey *key, int p, int a1, int a2, int a3)
+{
+       key->a1 = a1;
+       key->a2 = a2;
+       key->a3 = a3;
+       key->p = p;
+}
+
+static int checkvisit(MemArena *arena, GHash *gh, int p, int a1, int a2, int a3)
+{
+       tripairkey key, *key2;
+       
+       get_tripairkey(&key, p, a1, a2, a3);
+       if (BLI_ghash_haskey(gh, &key))
+               return 1;
+       
+       key2 = BLI_memarena_alloc(arena, sizeof(*key2));
+       *key2 = key;
+       BLI_ghash_insert(gh, key2, NULL);
+       
+       return 0;
+}
+
+int cloth_point_tri_moving_v3v3_f(float v1[2][3], int i1, float v2[2][3], int i2,
+                                   float v3[2][3],  int i3, float v4[2][3], int i4,
+                                   float normal[3], float bary[3], float *t, 
+                                                                  float *relnor, GHash *gh, MemArena *arena)
+{
+       if (checkvisit(arena, gh, i1, i2, i3, i4))
+               return 0;
+       
+       return eltopo_point_tri_moving_v3v3_f(v1, i1, v2, i2, v3, i3, v4, i4, normal, bary, t, relnor);
+}
+
+static CollPair* cloth_collision ( ModifierData *md1, ModifierData *md2, BVHTreeOverlap *overlap, 
+                                                                  CollPair *collpair, double dt, GHash *gh, MemArena *arena)
+{
+       ClothModifierData *clmd = ( ClothModifierData * ) md1;
+       CollisionModifierData *collmd = ( CollisionModifierData * ) md2;
+       MFace *face1=NULL, *face2 = NULL;
+       ClothVertex *verts1 = clmd->clothObject->verts;
+       double distance = 0;
+       float epsilon1 = clmd->coll_parms->epsilon;
+       float epsilon2 = BLI_bvhtree_getepsilon ( collmd->bvhtree );
+       float no[3], uv[3], t, relnor;
+       int i, i1, i2, i3, i4, i5, i6;
+       Cloth *cloth = clmd->clothObject;
+       float n1[3], sdis, p[3], l, n2[3], off[3], v1[2][3], v2[2][3], v3[2][3], v4[2][3], v5[2][3], v6[2][3];
+       int j, ret, bp1, bp2, bp3, ap1, ap2, ap3;
+       
+       face1 = & ( clmd->clothObject->mfaces[overlap->indexA] );
+       face2 = & ( collmd->mfaces[overlap->indexB] );
+
+       // check all 4 possible collisions
+       for ( i = 0; i < 4; i++ )
+       {
+               if ( i == 0 )
+               {
+                       // fill faceA
+                       ap1 = face1->v1;
+                       ap2 = face1->v2;
+                       ap3 = face1->v3;
+
+                       // fill faceB
+                       bp1 = face2->v1;
+                       bp2 = face2->v2;
+                       bp3 = face2->v3;
+               }
+               else if ( i == 1 )
+               {
+                       if ( face1->v4 )
+                       {
+                               // fill faceA
+                               ap1 = face1->v1;
+                               ap2 = face1->v3;
+                               ap3 = face1->v4;
+
+                               // fill faceB
+                               bp1 = face2->v1;
+                               bp2 = face2->v2;
+                               bp3 = face2->v3;
+                       }
+                       else {
+                               continue;
+                       }
+               }
+               if ( i == 2 )
+               {
+                       if ( face2->v4 )
+                       {
+                               // fill faceA
+                               ap1 = face1->v1;
+                               ap2 = face1->v2;
+                               ap3 = face1->v3;
+
+                               // fill faceB
+                               bp1 = face2->v1;
+                               bp2 = face2->v3;
+                               bp3 = face2->v4;
+                       }
+                       else {
+                               continue;
+                       }
+               }
+               else if ( i == 3 )
+               {
+                       if ( face1->v4 && face2->v4 )
+                       {
+                               // fill faceA
+                               ap1 = face1->v1;
+                               ap2 = face1->v3;
+                               ap3 = face1->v4;
+
+                               // fill faceB
+                               bp1 = face2->v1;
+                               bp2 = face2->v3;
+                               bp3 = face2->v4;
+                       }
+                       else {
+                               continue;
+                       }
+               }
+               
+               copy_v3_v3(v1[0], cloth->verts[ap1].txold); 
+               copy_v3_v3(v1[1], cloth->verts[ap1].tx);
+               copy_v3_v3(v2[0], cloth->verts[ap2].txold);
+               copy_v3_v3(v2[1], cloth->verts[ap2].tx);
+               copy_v3_v3(v3[0], cloth->verts[ap3].txold);
+               copy_v3_v3(v3[1], cloth->verts[ap3].tx);
+               
+               copy_v3_v3(v4[0], collmd->current_x[bp1].co);
+               copy_v3_v3(v4[1], collmd->current_xnew[bp1].co);
+               copy_v3_v3(v5[0], collmd->current_x[bp2].co);
+               copy_v3_v3(v5[1], collmd->current_xnew[bp2].co);
+               copy_v3_v3(v6[0], collmd->current_x[bp3].co);
+               copy_v3_v3(v6[1], collmd->current_xnew[bp3].co);
+               
+               normal_tri_v3(n2, v4[1], v5[1], v6[1]);
+               
+               sdis = clmd->coll_parms->distance_repel + epsilon2 + FLT_EPSILON;
+
+               /*apply a repulsion force, to help the solver along*/
+               copy_v3_v3(off, n2);
+               negate_v3(off);
+               if (isect_ray_plane_v3(v1[1], off, v4[1], v5[1], v6[1], &l, 0)) {
+                       if (l >= 0.0 && l < sdis) {
+                               mul_v3_fl(off, (l-sdis)*cloth->verts[ap1].mass*dt*clmd->coll_parms->repel_force*0.1);
+
+                               add_v3_v3(cloth->verts[ap1].tv, off);
+                               add_v3_v3(cloth->verts[ap2].tv, off);
+                               add_v3_v3(cloth->verts[ap3].tv, off);
+                       }
+               }
+
+               /*offset new positions a bit, to account for margins*/
+               copy_v3_v3(off, n2);
+               mul_v3_fl(off,  epsilon1 + epsilon2 + ALMOST_ZERO);
+               add_v3_v3(v4[1], off); add_v3_v3(v5[1], off); add_v3_v3(v6[1], off);
+               
+               i1 = ap1; i2 = ap2; i3 = ap3;
+               i4 = bp1+cloth->numverts; i5 = bp2+cloth->numverts; i6 = bp3+cloth->numverts;
+               
+               for (j=0; j<6; j++) {
+                       int collp;
+
+                       switch (j) {
+                       case 0:
+                               ret = cloth_point_tri_moving_v3v3_f(v1, i1, v4, i4, v5, i5, v6, i6, no, uv, &t, &relnor, gh, arena);
+                               collp = ap1;
+                               break;
+                       case 1:
+                               collp = ap2;
+                               ret = cloth_point_tri_moving_v3v3_f(v2, i2, v4, i4, v5, i5, v6, i6, no, uv, &t, &relnor, gh, arena);
+                               break;
+                       case 2:
+                               collp = ap3;
+                               ret = cloth_point_tri_moving_v3v3_f(v3, i3, v4, i4, v5, i5, v6, i6, no, uv, &t, &relnor, gh, arena);
+                               break;
+                       case 3:
+                               collp = bp1;
+                               ret = cloth_point_tri_moving_v3v3_f(v4, i4, v1, i1, v2, i2, v3, i3, no, uv, &t, &relnor, gh, arena);
+                               break;
+                       case 4:
+                               collp = bp2;                            
+                               ret = cloth_point_tri_moving_v3v3_f(v5, i5, v1, i1, v2, i2, v3, i3, no, uv, &t, &relnor, gh, arena);
+                               break;
+                       case 5:
+                               collp = bp3;
+                               ret = cloth_point_tri_moving_v3v3_f(v6, i6, v1, i1, v2, i2, v3, i3, no, uv, &t, &relnor, gh, arena);
+                               break;
+                       }
+                       
+                       /*cloth vert versus coll face*/
+                       if (ret && j < 3) {
+                               collpair->bp1 = bp1; collpair->bp2 = bp2; collpair->bp3 = bp3;
+                               collpair->collp = collp;
+                               
+                               copy_v3_v3(collpair->normal, no);
+                               mul_v3_v3fl(collpair->vector, collpair->normal, relnor);
+                               collpair->distance = relnor;
+                               collpair->time = t;
+                               
+                               copy_v3_v3(collpair->bary, uv);
+                               
+                               collpair->flag = COLLISION_USE_COLLFACE;
+                               collpair++;
+                       } else if (ret && j >= 3) { /*coll vert versus cloth face*/
+                               collpair->ap1 = ap1; collpair->ap2 = ap2; collpair->ap3 = ap3;
+                               collpair->collp = collp;
+                               
+                               copy_v3_v3(collpair->normal, no);
+                               mul_v3_v3fl(collpair->vector, collpair->normal, relnor);
+                               collpair->distance = relnor;
+                               collpair->time = t;
+                               
+                               copy_v3_v3(collpair->bary, uv);
+
+                               collpair->flag = 0;
+                               collpair++;
+                       }
+               }
+       }
+       
+       return collpair;
+}
+
+static void machine_epsilon_offset(Cloth *cloth) {
+       ClothVertex *cv;
+       int i, j;
+       
+       cv = cloth->verts;
+       for (i=0; i<cloth->numverts; i++, cv++) {
+               /*aggrevatingly enough, it's necassary to offset the coordinates
+                by a multiple of the 32-bit floating point epsilon when switching
+                into doubles*/
+               #define RNDSIGN (float)(-1*(BLI_rand()%2==0)|1)
+               for (j=0; j<3; j++) {
+                       cv->tx[j] += FLT_EPSILON*30.0f*RNDSIGN;
+                       cv->txold[j] += FLT_EPSILON*30.0f*RNDSIGN;
+                       cv->tv[j] += FLT_EPSILON*30.0f*RNDSIGN;
+               }               
+       }
+}
+
+#else /* !WITH_ELTOPO */
 
 //Determines collisions on overlap, collisions are written to collpair[i] and collision+number_collision_found is returned
-CollPair* cloth_collision ( ModifierData *md1, ModifierData *md2, BVHTreeOverlap *overlap, CollPair *collpair )
+static CollPair* cloth_collision ( ModifierData *md1, ModifierData *md2, 
+       BVHTreeOverlap *overlap, CollPair *collpair, float dt )
 {
        ClothModifierData *clmd = ( ClothModifierData * ) md1;
        CollisionModifierData *collmd = ( CollisionModifierData * ) md2;
+       Cloth *cloth = clmd->clothObject;
        MFace *face1=NULL, *face2 = NULL;
 #ifdef USE_BULLET
        ClothVertex *verts1 = clmd->clothObject->verts;
@@ -608,6 +1409,7 @@ CollPair* cloth_collision ( ModifierData *md1, ModifierData *md2, BVHTreeOverlap
        double distance = 0;
        float epsilon1 = clmd->coll_parms->epsilon;
        float epsilon2 = BLI_bvhtree_getepsilon ( collmd->bvhtree );
+       float n2[3], sdis, l;
        int i;
 
        face1 = & ( clmd->clothObject->mfaces[overlap->indexA] );
@@ -679,7 +1481,28 @@ CollPair* cloth_collision ( ModifierData *md1, ModifierData *md2, BVHTreeOverlap
                        else
                                break;
                }
+               
+               normal_tri_v3(n2, collmd->current_xnew[collpair->bp1].co, 
+                       collmd->current_xnew[collpair->bp2].co, 
+                       collmd->current_xnew[collpair->bp3].co);
+               
+               sdis = clmd->coll_parms->distance_repel + epsilon2 + FLT_EPSILON;
+               
+               /* apply a repulsion force, to help the solver along.
+                * this is kindof crude, it only tests one vert of the triangle */
+               if (isect_ray_plane_v3(cloth->verts[collpair->ap1].tx, n2, collmd->current_xnew[collpair->bp1].co, 
+                       collmd->current_xnew[collpair->bp2].co,
+                       collmd->current_xnew[collpair->bp3].co, &l, 0))
+               {
+                       if (l >= 0.0 && l < sdis) {
+                               mul_v3_fl(n2, (l-sdis)*cloth->verts[collpair->ap1].mass*dt*clmd->coll_parms->repel_force*0.1);
 
+                               add_v3_v3(cloth->verts[collpair->ap1].tv, n2);
+                               add_v3_v3(cloth->verts[collpair->ap2].tv, n2);
+                               add_v3_v3(cloth->verts[collpair->ap3].tv, n2);
+                       }
+               }
+               
 #ifdef USE_BULLET
                // calc distance + normal
                distance = plNearestPoints (
@@ -735,6 +1558,8 @@ CollPair* cloth_collision ( ModifierData *md1, ModifierData *md2, BVHTreeOverlap
        }
        return collpair;
 }
+#endif /* WITH_ELTOPO */
+
 
 #if 0
 static int cloth_collision_response_moving( ClothModifierData *clmd, CollisionModifierData *collmd, CollPair *collpair, CollPair *collision_end )
@@ -850,10 +1675,10 @@ static int cloth_collision_response_moving( ClothModifierData *clmd, CollisionMo
 #if 0
 static float projectPointOntoLine(float *p, float *a, float *b) 
 {
-   float ba[3], pa[3];
-   VECSUB(ba, b, a);
-   VECSUB(pa, p, a);
-   return INPR(pa, ba) / INPR(ba, ba);
+       float ba[3], pa[3];
+       VECSUB(ba, b, a);
+       VECSUB(pa, p, a);
+       return INPR(pa, ba) / INPR(ba, ba);
 }
 
 static void calculateEENormal(float *np1, float *np2, float *np3, float *np4,float *out_normal) 
@@ -1197,7 +2022,7 @@ static int cloth_collision_moving_edges ( ClothModifierData *clmd, CollisionModi
                        {
                                if(edgecollpair.p21==6 || edgecollpair.p22 == 6)
                                {
-                                       printf("dist: %f, sol[k]: %lf, sol2[k]: %lf\n", distance, solution[k], solution2[k]);
+                                       printf("dist: %f, sol[k]: %f, sol2[k]: %f\n", distance, solution[k], solution2[k]);
                                        printf("a1: %f, a2: %f, b1: %f, b2: %f\n", x1[0], x2[0], x3[0], v1[0]);
                                        printf("b21: %d, b22: %d\n", edgecollpair.p21, edgecollpair.p22);
                                }
@@ -1307,7 +2132,7 @@ static int cloth_collision_moving ( ClothModifierData *clmd, CollisionModifierDa
 }
 #endif
 
-static void add_collision_object(Object ***objs, int *numobj, int *maxobj, Object *ob, Object *self, int level)
+static void add_collision_object(Object ***objs, unsigned int *numobj, unsigned int *maxobj, Object *ob, Object *self, int level)
 {
        CollisionModifierData *cmd= NULL;
 
@@ -1342,12 +2167,12 @@ static void add_collision_object(Object ***objs, int *numobj, int *maxobj, Objec
 
 // return all collision objects in scene
 // collision object will exclude self 
-Object **get_collisionobjects(Scene *scene, Object *self, Group *group, int *numcollobj)
+Object **get_collisionobjects(Scene *scene, Object *self, Group *group, unsigned int *numcollobj)
 {
        Base *base;
        Object **objs;
        GroupObject *go;
-       int numobj= 0, maxobj= 100;
+       unsigned int numobj= 0, maxobj= 100;
        
        objs= MEM_callocN(sizeof(Object *)*maxobj, "CollisionObjectsArray");
 
@@ -1358,9 +2183,9 @@ Object **get_collisionobjects(Scene *scene, Object *self, Group *group, int *num
                        add_collision_object(&objs, &numobj, &maxobj, go->ob, self, 0);
        }
        else {
-               Scene *sce; /* for SETLOOPER macro */
+               Scene *sce_iter;
                /* add objects in same layer in scene */
-               for(SETLOOPER(scene, base)) {
+               for(SETLOOPER(scene, sce_iter, base)) {
                        if(base->lay & self->lay)
                                add_collision_object(&objs, &numobj, &maxobj, base->object, self, 0);
 
@@ -1417,11 +2242,11 @@ ListBase *get_collider_cache(Scene *scene, Object *self, Group *group)
                        add_collider_cache_object(&objs, go->ob, self, 0);
        }
        else {
-               Scene *sce; /* for SETLOOPER macro */
+               Scene *sce_iter;
                Base *base;
 
                /* add objects in same layer in scene */
-               for(SETLOOPER(scene, base)) {
+               for(SETLOOPER(scene, sce_iter, base)) {
                        if(!self || (base->lay & self->lay))
                                add_collider_cache_object(&objs, base->object, self, 0);
 
@@ -1440,29 +2265,57 @@ void free_collider_cache(ListBase **colliders)
        }
 }
 
-static void cloth_bvh_objcollisions_nearcheck ( ClothModifierData * clmd, CollisionModifierData *collmd, CollPair **collisions, CollPair **collisions_index, int numresult, BVHTreeOverlap *overlap)
+
+static void cloth_bvh_objcollisions_nearcheck ( ClothModifierData * clmd, CollisionModifierData *collmd,
+       CollPair **collisions, CollPair **collisions_index, int numresult, BVHTreeOverlap *overlap, double dt)
 {
        int i;
+#ifdef WITH_ELTOPO
+       GHash *visithash = BLI_ghash_new(edgepair_hash, edgepair_cmp, "visthash, collision.c");
+       GHash *tri_visithash = BLI_ghash_new(tripair_hash, tripair_cmp, "tri_visthash, collision.c");
+       MemArena *arena = BLI_memarena_new(1<<16, "edge hash arena, collision.c");
+#endif
        
-       *collisions = ( CollPair* ) MEM_mallocN ( sizeof ( CollPair ) * numresult * 4, "collision array" ); //*4 since cloth_collision_static can return more than 1 collision
+       *collisions = ( CollPair* ) MEM_mallocN ( sizeof ( CollPair ) * numresult * 64, "collision array" ); //*4 since cloth_collision_static can return more than 1 collision
        *collisions_index = *collisions;
+       
+#ifdef WITH_ELTOPO
+       machine_epsilon_offset(clmd->clothObject);
+
+       for ( i = 0; i < numresult; i++ )
+       {
+               *collisions_index = cloth_collision ( ( ModifierData * ) clmd, ( ModifierData * ) collmd,
+                                                                                         overlap+i, *collisions_index, dt, tri_visithash, arena );
+       }
 
        for ( i = 0; i < numresult; i++ )
        {
-               *collisions_index = cloth_collision ( ( ModifierData * ) clmd, ( ModifierData * ) collmd, overlap+i, *collisions_index );
+               *collisions_index = cloth_edge_collision ( ( ModifierData * ) clmd, ( ModifierData * ) collmd,
+                                                                                                  overlap+i, *collisions_index, visithash, arena );
        }
+       BLI_ghash_free(visithash, NULL, NULL);
+       BLI_ghash_free(tri_visithash, NULL, NULL);
+       BLI_memarena_free(arena);
+#else /* WITH_ELTOPO */
+       for ( i = 0; i < numresult; i++ )
+       {
+               *collisions_index = cloth_collision ( ( ModifierData * ) clmd, ( ModifierData * ) collmd,
+                                                                                         overlap+i, *collisions_index, dt );
+       }
+#endif /* WITH_ELTOPO */
+
 }
 
 static int cloth_bvh_objcollisions_resolve ( ClothModifierData * clmd, CollisionModifierData *collmd, CollPair *collisions, CollPair *collisions_index)
 {
        Cloth *cloth = clmd->clothObject;
-       int i=0, j = 0, numfaces = 0, numverts = 0;
+       int i=0, j = 0, /*numfaces = 0,*/ numverts = 0;
        ClothVertex *verts = NULL;
        int ret = 0;
        int result = 0;
        float tnull[3] = {0,0,0};
        
-       numfaces = clmd->clothObject->numfaces;
+       /*numfaces = clmd->clothObject->numfaces;*/ /*UNUSED*/
        numverts = clmd->clothObject->numverts;
  
        verts = cloth->verts;
@@ -1475,18 +2328,26 @@ static int cloth_bvh_objcollisions_resolve ( ClothModifierData * clmd, Collision
 
                if ( collmd->bvhtree )
                {
+#ifdef WITH_ELTOPO
+                       result += cloth_collision_response_moving(clmd, collmd, collisions, collisions_index);
+                       result += cloth_edge_collision_response_moving(clmd, collmd, collisions, collisions_index);
+#else
                        result += cloth_collision_response_static ( clmd, collmd, collisions, collisions_index );
-
+#endif
+#ifdef WITH_ELTOPO
+                       {
+#else
                        // apply impulses in parallel
                        if ( result )
                        {
+#endif
                                for ( i = 0; i < numverts; i++ )
                                {
                                        // calculate "velocities" (just xnew = xold + v; no dt in v)
                                        if ( verts[i].impulse_count )
                                        {
                                                VECADDMUL ( verts[i].tv, verts[i].impulse, 1.0f / verts[i].impulse_count );
-                                               VECCOPY ( verts[i].impulse, tnull );
+                                               copy_v3_v3 ( verts[i].impulse, tnull );
                                                verts[i].impulse_count = 0;
 
                                                ret++;
@@ -1503,16 +2364,16 @@ int cloth_bvh_objcollision (Object *ob, ClothModifierData * clmd, float step, fl
 {
        Cloth *cloth= clmd->clothObject;
        BVHTree *cloth_bvh= cloth->bvhtree;
-       int i=0, numfaces = 0, numverts = 0, k, l, j;
+       unsigned int i=0, numfaces = 0, numverts = 0, k, l, j;
        int rounds = 0; // result counts applied collisions; ic is for debug output;
        ClothVertex *verts = NULL;
        int ret = 0, ret2 = 0;
        Object **collobjs = NULL;
-       int numcollobj = 0;
+       unsigned int numcollobj = 0;
 
        if ((clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_COLLOBJ) || cloth_bvh==NULL)
                return 0;
-
+       
        verts = cloth->verts;
        numfaces = cloth->numfaces;
        numverts = cloth->numverts;
@@ -1545,12 +2406,13 @@ int cloth_bvh_objcollision (Object *ob, ClothModifierData * clmd, float step, fl
                        Object *collob= collobjs[i];
                        CollisionModifierData *collmd = (CollisionModifierData*)modifiers_findByType(collob, eModifierType_Collision);
                        BVHTreeOverlap *overlap = NULL;
-                       int result = 0;
+                       unsigned int result = 0;
                        
                        if(!collmd->bvhtree)
                                continue;
                        
                        /* move object to position (step) in time */
+                       
                        collision_move_object ( collmd, step + dt, step );
                        
                        /* search for overlapping collision pairs */
@@ -1559,7 +2421,8 @@ int cloth_bvh_objcollision (Object *ob, ClothModifierData * clmd, float step, fl
                        // go to next object if no overlap is there
                        if( result && overlap ) {
                                /* check if collisions really happen (costly near check) */
-                               cloth_bvh_objcollisions_nearcheck ( clmd, collmd, &collisions[i], &collisions_index[i], result, overlap);
+                               cloth_bvh_objcollisions_nearcheck ( clmd, collmd, &collisions[i], 
+                                       &collisions_index[i], result, overlap, dt/(float)clmd->coll_parms->loop_count);
                        
                                // resolve nearby collisions
                                ret += cloth_bvh_objcollisions_resolve ( clmd, collmd, collisions[i],  collisions_index[i]);
@@ -1605,11 +2468,11 @@ int cloth_bvh_objcollision (Object *ob, ClothModifierData * clmd, float step, fl
                ////////////////////////////////////////////////////////////
                if ( clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_SELF )
                {
-                       for(l = 0; l < clmd->coll_parms->self_loop_count; l++)
+                       for(l = 0; l < (unsigned int)clmd->coll_parms->self_loop_count; l++)
                        {
                                // TODO: add coll quality rounds again
                                BVHTreeOverlap *overlap = NULL;
-                               int result = 0;
+                               unsigned int result = 0;
        
                                // collisions = 1;
                                verts = cloth->verts; // needed for openMP
@@ -1715,5 +2578,5 @@ int cloth_bvh_objcollision (Object *ob, ClothModifierData * clmd, float step, fl
        if(collobjs)
                MEM_freeN(collobjs);
 
-       return MIN2 ( ret, 1 );
+       return 1|MIN2 ( ret, 1 );
 }