numerous input and physics
[carveJwlIkooP6JGAAIwe30JlM.git] / rigidbody.h
index 10b4359f56537641354c59e982e0d9d8a37b6098..04d5a9c9830c824d466b7c3fb7cff82364556726 100644 (file)
@@ -103,6 +103,7 @@ VG_STATIC struct contact
          normal_mass, tangent_mass[2];
 
    u32 element_id;
+   int cluster;
 }
 rb_contact_buffer[256];
 VG_STATIC int rb_contact_count = 0;
@@ -1247,12 +1248,19 @@ VG_STATIC int rb_sphere_sphere( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
    return 0;
 }
 
+#define RIGIDBODY_DYNAMIC_MESH_EDGES
+
 VG_STATIC int rb_sphere_triangle( rigidbody *rba, rigidbody *rbb, 
                                   v3f tri[3], rb_ct *buf )
 {
    v3f delta, co;
 
+#ifdef RIGIDBODY_DYNAMIC_MESH_EDGES
+   closest_on_triangle( rba->co, tri, co );
+#else
    closest_on_triangle_1( rba->co, tri, co );
+#endif
+
    v3_sub( rba->co, co, delta );
 
    vg_line( rba->co, co, 0xffff0000 );
@@ -1289,24 +1297,142 @@ VG_STATIC int rb_sphere_scene( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
    scene *sc = rbb->inf.scene.bh_scene->user;
    
    u32 geo[128];
-   v3f tri[3];
-   int len = bh_select( rbb->inf.scene.bh_scene, rba->bbx_world, geo, 128 );
 
+   int len = bh_select( rbb->inf.scene.bh_scene, rba->bbx_world, geo, 128 );
    int count = 0;
 
+#ifdef RIGIDBODY_DYNAMIC_MESH_EDGES
+   /* !experimental! build edge array on the fly. time could be improved! */
+
+   v3f co_picture[128*3];
+   int unique_cos = 0;
+
+   struct face_info
+   {
+      int unique_cos[3];   /* indexes co_picture array */
+      int collided;
+      v3f normal;
+      u32 element_id;
+   }
+   faces[128];
+
+   /* create geometry picture */
+   for( int i=0; i<len; i++ )
+   {
+      u32 *tri_indices = &sc->arrindices[ geo[i]*3 ];
+      struct face_info *inf = &faces[i];
+      inf->element_id = tri_indices[0];
+      inf->collided = 0;
+
+      for( int j=0; j<3; j++ )
+      {
+         struct mdl_vert *pvert = &sc->arrvertices[tri_indices[j]];
+
+         for( int k=0; k<unique_cos; k++ )
+         {
+            if( v3_dist( pvert->co, co_picture[k] ) < 0.01f*0.01f )
+            {
+               inf->unique_cos[j] = k;
+               goto next_vert;
+            }
+         }
+
+         inf->unique_cos[j] = unique_cos;
+         v3_copy( pvert->co, co_picture[ unique_cos ++ ] );
+next_vert:;
+      }
+
+      v3f ab, ac;
+      v3_sub( co_picture[inf->unique_cos[2]], 
+              co_picture[inf->unique_cos[0]], ab );
+
+      v3_sub( co_picture[inf->unique_cos[1]],
+              co_picture[inf->unique_cos[0]], ac );
+      v3_cross( ac, ab, inf->normal );
+      v3_normalize( inf->normal );
+   }
+
+
+   /* build edges brute force */
+   int edge_picture[ 128*3 ][4];
+   int unique_edges = 0;
+
+   for( int i=0; i<len; i++ )
+   {
+      struct face_info *inf = &faces[i];
+      
+      for( int j=0; j<3; j++ )
+      {
+         int i0 = j,
+             i1 = (j+1)%3,
+             e0 = VG_MIN( inf->unique_cos[i0], inf->unique_cos[i1] ),
+             e1 = VG_MAX( inf->unique_cos[i0], inf->unique_cos[i1] ),
+             matched = 0;
+
+         for( int k=0; k<unique_edges; k ++ )
+         {
+            int k0 = VG_MIN( edge_picture[k][0], edge_picture[k][1] ),
+                k1 = VG_MAX( edge_picture[k][0], edge_picture[k][1] );
+
+            /* matched ! */
+            if( (k0 == e0) && (k1 == e1) )
+            {
+               edge_picture[ k ][3] = i;
+               matched = 1;
+               break;
+            }
+         }
+      
+         if( !matched )
+         {
+            /* create new edge */
+            edge_picture[ unique_edges ][0] = inf->unique_cos[i0];
+            edge_picture[ unique_edges ][1] = inf->unique_cos[i1];
+
+            edge_picture[ unique_edges ][2] = i;
+            edge_picture[ unique_edges ][3] = -1;
+
+            unique_edges ++;
+         }
+      }
+   }
+#endif
+
+   v3f tri[3];
+
    for( int i=0; i<len; i++ )
    {
+#ifdef RIGIDBODY_DYNAMIC_MESH_EDGES
+      struct face_info *inf = &faces[i];
+
+      float *v0 = co_picture[inf->unique_cos[0]],
+            *v1 = co_picture[inf->unique_cos[1]],
+            *v2 = co_picture[inf->unique_cos[2]];
+
+      v3_copy( v0, tri[0] );
+      v3_copy( v1, tri[1] );
+      v3_copy( v2, tri[2] );
+
+      buf[count].element_id = inf->element_id;
+#else
       u32 *ptri = &sc->arrindices[ geo[i]*3 ];
 
       for( int j=0; j<3; j++ )
          v3_copy( sc->arrvertices[ptri[j]].co, tri[j] );
-
-      vg_line(tri[0],tri[1],0xff00ff00 );
-      vg_line(tri[1],tri[2],0xff00ff00 );
-      vg_line(tri[2],tri[0],0xff00ff00 );
       
       buf[count].element_id = ptri[0];
-      count += rb_sphere_triangle( rba, rbb, tri, buf+count );
+#endif
+
+      vg_line( tri[0],tri[1],0x10ffffff );
+      vg_line( tri[1],tri[2],0x10ffffff );
+      vg_line( tri[2],tri[0],0x10ffffff );
+
+      int hits = rb_sphere_triangle( rba, rbb, tri, buf+count );
+#ifdef RIGIDBODY_DYNAMIC_MESH_EDGES
+      if( hits )
+         inf->collided = 1;
+#endif
+      count += hits;
 
       if( count == 12 )
       {
@@ -1315,6 +1441,62 @@ VG_STATIC int rb_sphere_scene( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
       }
    }
 
+#ifdef RIGIDBODY_DYNAMIC_MESH_EDGES
+   for( int i=0; i<unique_edges; i++ )
+   {
+      int *edge = edge_picture[i];
+
+      if( edge[3] == -1 )
+         continue;
+
+      struct face_info *inf_i = &faces[edge[2]],
+                       *inf_j = &faces[edge[3]];
+      
+      if( inf_i->collided || inf_j->collided )
+         continue;
+
+      v3f co, delta;
+      closest_point_segment( co_picture[edge[0]], co_picture[edge[1]], 
+                             rba->co, co );
+   
+      v3_sub( rba->co, co, delta );
+      float d2 = v3_length2( delta ),
+            r  = rba->inf.sphere.radius;
+
+      if( d2 < r*r )
+      {
+         float d = sqrtf(d2);
+
+         v3_muls( delta, 1.0f/d, delta );
+         float c0 = v3_dot( inf_i->normal, delta ),
+               c1 = v3_dot( inf_j->normal, delta );
+
+         if( c0 < 0.0f || c1 < 0.0f )
+            continue;
+
+         rb_ct *ct = buf+count;
+            
+         v3_muls( inf_i->normal, c0, ct->n );
+         v3_muladds( ct->n, inf_j->normal, c1, ct->n );
+         v3_normalize( ct->n );
+
+         v3_copy( co, ct->co );
+         ct->p = r-d;
+         ct->rba = rba;
+         ct->rbb = rbb;
+         ct->element_id = inf_i->element_id;
+
+         count ++;
+
+         if( count == 12 )
+         {
+            vg_warn( "Geometry too dense!\n" );
+            return count;
+         }
+      }
+   }
+#endif
+
    return count;
 }