Blender  V2.59
cloth.c
Go to the documentation of this file.
00001 /*
00002  * $Id: cloth.c 36419 2011-05-01 21:39:13Z joeedh $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is Copyright (C) Blender Foundation
00021  * All rights reserved.
00022  *
00023  * Contributor(s): Daniel Genrich
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  */
00027 
00033 #include "MEM_guardedalloc.h"
00034 
00035 #include "DNA_cloth_types.h"
00036 #include "DNA_scene_types.h"
00037 #include "DNA_object_types.h"
00038 #include "DNA_meshdata_types.h"
00039 
00040 #include "BLI_math.h"
00041 #include "BLI_edgehash.h"
00042 #include "BLI_utildefines.h"
00043 
00044 #include "BKE_cdderivedmesh.h"
00045 #include "BKE_cloth.h"
00046 #include "BKE_effect.h"
00047 #include "BKE_global.h"
00048 #include "BKE_modifier.h"
00049 #include "BKE_pointcache.h"
00050 
00051 
00052 #ifdef _WIN32
00053 void tstart ( void )
00054 {}
00055 void tend ( void )
00056 {
00057 }
00058 double tval( void )
00059 {
00060         return 0;
00061 }
00062 #else
00063 #include <sys/time.h>
00064                          static struct timeval _tstart, _tend;
00065          static struct timezone tz;
00066          void tstart ( void )
00067 {
00068         gettimeofday ( &_tstart, &tz );
00069 }
00070 void tend ( void )
00071 {
00072         gettimeofday ( &_tend,&tz );
00073 }
00074 double tval(void)
00075 {
00076         double t1, t2;
00077         t1 = ( double ) _tstart.tv_sec + ( double ) _tstart.tv_usec/ ( 1000*1000 );
00078         t2 = ( double ) _tend.tv_sec + ( double ) _tend.tv_usec/ ( 1000*1000 );
00079         return t2-t1;
00080 }
00081 #endif
00082 
00083 /* Our available solvers. */
00084 // 255 is the magic reserved number, so NEVER try to put 255 solvers in here!
00085 // 254 = MAX!
00086 static CM_SOLVER_DEF    solvers [] =
00087 {
00088         { "Implicit", CM_IMPLICIT, implicit_init, implicit_solver, implicit_free },
00089                 // { "Implicit C++", CM_IMPLICITCPP, implicitcpp_init, implicitcpp_solver, implicitcpp_free },
00090 };
00091 
00092 /* ********** cloth engine ******* */
00093 /* Prototypes for internal functions.
00094 */
00095 static void cloth_to_object (Object *ob,  ClothModifierData *clmd, DerivedMesh *dm);
00096 static void cloth_from_mesh ( ClothModifierData *clmd, DerivedMesh *dm );
00097 static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *dm, float framenr, int first);
00098 static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm );
00099 static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm );
00100 
00101 
00102 /******************************************************************************
00103 *
00104 * External interface called by modifier.c clothModifier functions.
00105 *
00106 ******************************************************************************/
00113 void cloth_init ( ClothModifierData *clmd )
00114 {       
00115         /* Initialize our new data structure to reasonable values. */
00116         clmd->sim_parms->gravity [0] = 0.0;
00117         clmd->sim_parms->gravity [1] = 0.0;
00118         clmd->sim_parms->gravity [2] = -9.81;
00119         clmd->sim_parms->structural = 15.0;
00120         clmd->sim_parms->shear = 15.0;
00121         clmd->sim_parms->bending = 0.5;
00122         clmd->sim_parms->Cdis = 5.0; 
00123         clmd->sim_parms->Cvi = 1.0;
00124         clmd->sim_parms->mass = 0.3f;
00125         clmd->sim_parms->stepsPerFrame = 5;
00126         clmd->sim_parms->flags = 0;
00127         clmd->sim_parms->solver_type = 0;
00128         clmd->sim_parms->preroll = 0;
00129         clmd->sim_parms->maxspringlen = 10;
00130         clmd->sim_parms->vgroup_mass = 0;
00131         clmd->sim_parms->avg_spring_len = 0.0;
00132         clmd->sim_parms->presets = 2; /* cotton as start setting */
00133         clmd->sim_parms->timescale = 1.0f; /* speed factor, describes how fast cloth moves */
00134         clmd->sim_parms->reset = 0;
00135         
00136         clmd->coll_parms->self_friction = 5.0;
00137         clmd->coll_parms->friction = 5.0;
00138         clmd->coll_parms->loop_count = 2;
00139         clmd->coll_parms->epsilon = 0.015f;
00140         clmd->coll_parms->flags = CLOTH_COLLSETTINGS_FLAG_ENABLED;
00141         clmd->coll_parms->collision_list = NULL;
00142         clmd->coll_parms->self_loop_count = 1.0;
00143         clmd->coll_parms->selfepsilon = 0.75;
00144 
00145         /* These defaults are copied from softbody.c's
00146         * softbody_calc_forces() function.
00147         */
00148         clmd->sim_parms->eff_force_scale = 1000.0;
00149         clmd->sim_parms->eff_wind_scale = 250.0;
00150 
00151         // also from softbodies
00152         clmd->sim_parms->maxgoal = 1.0f;
00153         clmd->sim_parms->mingoal = 0.0f;
00154         clmd->sim_parms->defgoal = 0.0f;
00155         clmd->sim_parms->goalspring = 1.0f;
00156         clmd->sim_parms->goalfrict = 0.0f;
00157         clmd->sim_parms->velocity_smooth = 0.0f;
00158 
00159         if(!clmd->sim_parms->effector_weights)
00160                 clmd->sim_parms->effector_weights = BKE_add_effector_weights(NULL);
00161 
00162         if(clmd->point_cache)
00163                 clmd->point_cache->step = 1;
00164 }
00165 
00166 static BVHTree *bvhselftree_build_from_cloth (ClothModifierData *clmd, float epsilon)
00167 {
00168         unsigned int i;
00169         BVHTree *bvhtree;
00170         Cloth *cloth;
00171         ClothVertex *verts;
00172         float co[12];
00173 
00174         if(!clmd)
00175                 return NULL;
00176 
00177         cloth = clmd->clothObject;
00178 
00179         if(!cloth)
00180                 return NULL;
00181         
00182         verts = cloth->verts;
00183         
00184         // in the moment, return zero if no faces there
00185         if(!cloth->numverts)
00186                 return NULL;
00187         
00188         // create quadtree with k=26
00189         bvhtree = BLI_bvhtree_new(cloth->numverts, epsilon, 4, 6);
00190         
00191         // fill tree
00192         for(i = 0; i < cloth->numverts; i++, verts++)
00193         {
00194                 VECCOPY(&co[0*3], verts->xold);
00195                 
00196                 BLI_bvhtree_insert(bvhtree, i, co, 1);
00197         }
00198         
00199         // balance tree
00200         BLI_bvhtree_balance(bvhtree);
00201         
00202         return bvhtree;
00203 }
00204 
00205 static BVHTree *bvhtree_build_from_cloth (ClothModifierData *clmd, float epsilon)
00206 {
00207         unsigned int i;
00208         BVHTree *bvhtree;
00209         Cloth *cloth;
00210         ClothVertex *verts;
00211         MFace *mfaces;
00212         float co[12];
00213 
00214         if(!clmd)
00215                 return NULL;
00216 
00217         cloth = clmd->clothObject;
00218 
00219         if(!cloth)
00220                 return NULL;
00221         
00222         verts = cloth->verts;
00223         mfaces = cloth->mfaces;
00224         
00225         // in the moment, return zero if no faces there
00226         if(!cloth->numfaces)
00227                 return NULL;
00228         
00229         // create quadtree with k=26
00230         bvhtree = BLI_bvhtree_new(cloth->numfaces, epsilon, 4, 26);
00231         
00232         // fill tree
00233         for(i = 0; i < cloth->numfaces; i++, mfaces++)
00234         {
00235                 VECCOPY(&co[0*3], verts[mfaces->v1].xold);
00236                 VECCOPY(&co[1*3], verts[mfaces->v2].xold);
00237                 VECCOPY(&co[2*3], verts[mfaces->v3].xold);
00238                 
00239                 if(mfaces->v4)
00240                         VECCOPY(&co[3*3], verts[mfaces->v4].xold);
00241                 
00242                 BLI_bvhtree_insert(bvhtree, i, co, (mfaces->v4 ? 4 : 3));
00243         }
00244         
00245         // balance tree
00246         BLI_bvhtree_balance(bvhtree);
00247         
00248         return bvhtree;
00249 }
00250 
00251 void bvhtree_update_from_cloth(ClothModifierData *clmd, int moving)
00252 {       
00253         unsigned int i = 0;
00254         Cloth *cloth = clmd->clothObject;
00255         BVHTree *bvhtree = cloth->bvhtree;
00256         ClothVertex *verts = cloth->verts;
00257         MFace *mfaces;
00258         float co[12], co_moving[12];
00259         int ret = 0;
00260         
00261         if(!bvhtree)
00262                 return;
00263         
00264         mfaces = cloth->mfaces;
00265         
00266         // update vertex position in bvh tree
00267         if(verts && mfaces)
00268         {
00269                 for(i = 0; i < cloth->numfaces; i++, mfaces++)
00270                 {
00271                         VECCOPY(&co[0*3], verts[mfaces->v1].txold);
00272                         VECCOPY(&co[1*3], verts[mfaces->v2].txold);
00273                         VECCOPY(&co[2*3], verts[mfaces->v3].txold);
00274                         
00275                         if(mfaces->v4)
00276                                 VECCOPY(&co[3*3], verts[mfaces->v4].txold);
00277                 
00278                         // copy new locations into array
00279                         if(moving)
00280                         {
00281                                 // update moving positions
00282                                 VECCOPY(&co_moving[0*3], verts[mfaces->v1].tx);
00283                                 VECCOPY(&co_moving[1*3], verts[mfaces->v2].tx);
00284                                 VECCOPY(&co_moving[2*3], verts[mfaces->v3].tx);
00285                                 
00286                                 if(mfaces->v4)
00287                                         VECCOPY(&co_moving[3*3], verts[mfaces->v4].tx);
00288                                 
00289                                 ret = BLI_bvhtree_update_node(bvhtree, i, co, co_moving, (mfaces->v4 ? 4 : 3));
00290                         }
00291                         else
00292                         {
00293                                 ret = BLI_bvhtree_update_node(bvhtree, i, co, NULL, (mfaces->v4 ? 4 : 3));
00294                         }
00295                         
00296                         // check if tree is already full
00297                         if(!ret)
00298                                 break;
00299                 }
00300                 
00301                 BLI_bvhtree_update_tree(bvhtree);
00302         }
00303 }
00304 
00305 void bvhselftree_update_from_cloth(ClothModifierData *clmd, int moving)
00306 {       
00307         unsigned int i = 0;
00308         Cloth *cloth = clmd->clothObject;
00309         BVHTree *bvhtree = cloth->bvhselftree;
00310         ClothVertex *verts = cloth->verts;
00311         MFace *mfaces;
00312         float co[12], co_moving[12];
00313         int ret = 0;
00314         
00315         if(!bvhtree)
00316                 return;
00317         
00318         mfaces = cloth->mfaces;
00319         
00320         // update vertex position in bvh tree
00321         if(verts && mfaces)
00322         {
00323                 for(i = 0; i < cloth->numverts; i++, verts++)
00324                 {
00325                         VECCOPY(&co[0*3], verts->txold);
00326                         
00327                         // copy new locations into array
00328                         if(moving)
00329                         {
00330                                 // update moving positions
00331                                 VECCOPY(&co_moving[0*3], verts->tx);
00332                                 
00333                                 ret = BLI_bvhtree_update_node(bvhtree, i, co, co_moving, 1);
00334                         }
00335                         else
00336                         {
00337                                 ret = BLI_bvhtree_update_node(bvhtree, i, co, NULL, 1);
00338                         }
00339                         
00340                         // check if tree is already full
00341                         if(!ret)
00342                                 break;
00343                 }
00344                 
00345                 BLI_bvhtree_update_tree(bvhtree);
00346         }
00347 }
00348 
00349 void cloth_clear_cache(Object *ob, ClothModifierData *clmd, float framenr)
00350 {
00351         PTCacheID pid;
00352         
00353         BKE_ptcache_id_from_cloth(&pid, ob, clmd);
00354 
00355         // don't do anything as long as we're in editmode!
00356         if(pid.cache->edit && ob->mode & OB_MODE_PARTICLE_EDIT)
00357                 return;
00358         
00359         BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_AFTER, framenr);
00360 }
00361 
00362 static int do_init_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *result, int framenr)
00363 {
00364         PointCache *cache;
00365 
00366         cache= clmd->point_cache;
00367 
00368         /* initialize simulation data if it didn't exist already */
00369         if(clmd->clothObject == NULL) { 
00370                 if(!cloth_from_object(ob, clmd, result, framenr, 1)) {
00371                         BKE_ptcache_invalidate(cache);
00372                         return 0;
00373                 }
00374         
00375                 if(clmd->clothObject == NULL) {
00376                         BKE_ptcache_invalidate(cache);
00377                         return 0;
00378                 }
00379         
00380                 implicit_set_positions(clmd);
00381         }
00382 
00383         return 1;
00384 }
00385 
00386 static int do_step_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *result, int framenr)
00387 {
00388         ClothVertex *verts = NULL;
00389         Cloth *cloth;
00390         ListBase *effectors = NULL;
00391         MVert *mvert;
00392         unsigned int i = 0;
00393         int ret = 0;
00394 
00395         /* simulate 1 frame forward */
00396         cloth = clmd->clothObject;
00397         verts = cloth->verts;
00398         mvert = result->getVertArray(result);
00399 
00400         /* force any pinned verts to their constrained location. */
00401         for(i = 0; i < clmd->clothObject->numverts; i++, verts++) {
00402                 /* save the previous position. */
00403                 VECCOPY(verts->xold, verts->xconst);
00404                 VECCOPY(verts->txold, verts->x);
00405 
00406                 /* Get the current position. */
00407                 VECCOPY(verts->xconst, mvert[i].co);
00408                 mul_m4_v3(ob->obmat, verts->xconst);
00409         }
00410 
00411         effectors = pdInitEffectors(clmd->scene, ob, NULL, clmd->sim_parms->effector_weights);
00412         
00413         tstart();
00414 
00415         /* call the solver. */
00416         if(solvers [clmd->sim_parms->solver_type].solver)
00417                 ret = solvers[clmd->sim_parms->solver_type].solver(ob, framenr, clmd, effectors);
00418 
00419         tend();
00420 
00421         pdEndEffectors(&effectors);
00422 
00423         // printf ( "%f\n", ( float ) tval() );
00424         
00425         return ret;
00426 }
00427 
00428 /************************************************
00429  * clothModifier_do - main simulation function
00430 ************************************************/
00431 DerivedMesh *clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, DerivedMesh *dm)
00432 {
00433         DerivedMesh *result;
00434         PointCache *cache;
00435         PTCacheID pid;
00436         float timescale;
00437         int framenr, startframe, endframe;
00438         int cache_result;
00439 
00440         clmd->scene= scene;     /* nice to pass on later :) */
00441         framenr= (int)scene->r.cfra;
00442         cache= clmd->point_cache;
00443         result = CDDM_copy(dm);
00444 
00445         BKE_ptcache_id_from_cloth(&pid, ob, clmd);
00446         BKE_ptcache_id_time(&pid, scene, framenr, &startframe, &endframe, &timescale);
00447         clmd->sim_parms->timescale= timescale;
00448 
00449         if(!result) {
00450                 BKE_ptcache_invalidate(cache);
00451                 return dm;
00452         }
00453 
00454         if(clmd->sim_parms->reset
00455                 || (framenr == (startframe - clmd->sim_parms->preroll) && clmd->sim_parms->preroll != 0)
00456                 || (clmd->clothObject && result->getNumVerts(result) != clmd->clothObject->numverts))
00457         {
00458                 clmd->sim_parms->reset = 0;
00459                 cache->flag |= PTCACHE_OUTDATED;
00460                 BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
00461                 BKE_ptcache_validate(cache, 0);
00462                 cache->last_exact= 0;
00463                 cache->flag &= ~PTCACHE_REDO_NEEDED;
00464                 return result;
00465         }
00466         
00467         // unused in the moment, calculated separately in implicit.c
00468         clmd->sim_parms->dt = clmd->sim_parms->timescale / clmd->sim_parms->stepsPerFrame;
00469 
00470         /* handle continuous simulation with the play button */
00471         if(BKE_ptcache_get_continue_physics() || ((clmd->sim_parms->preroll > 0) && (framenr > startframe - clmd->sim_parms->preroll) && (framenr < startframe))) {
00472                 BKE_ptcache_invalidate(cache);
00473 
00474                 /* do simulation */
00475                 if(!do_init_cloth(ob, clmd, dm, framenr))
00476                         return result;
00477 
00478                 do_step_cloth(ob, clmd, dm, framenr);
00479                 cloth_to_object(ob, clmd, result);
00480 
00481                 return result;
00482         }
00483 
00484         /* simulation is only active during a specific period */
00485         if(framenr < startframe) {
00486                 BKE_ptcache_invalidate(cache);
00487                 return result;
00488         }
00489         else if(framenr > endframe) {
00490                 framenr= endframe;
00491         }
00492 
00493         /* initialize simulation data if it didn't exist already */
00494         if(!do_init_cloth(ob, clmd, dm, framenr))
00495                 return result;
00496 
00497         if((framenr == startframe) && (clmd->sim_parms->preroll == 0)) {
00498                 BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
00499                 do_init_cloth(ob, clmd, dm, framenr);
00500                 BKE_ptcache_validate(cache, framenr);
00501                 cache->flag &= ~PTCACHE_REDO_NEEDED;
00502                 return result;
00503         }
00504 
00505         /* try to read from cache */
00506         cache_result = BKE_ptcache_read(&pid, (float)framenr+scene->r.subframe);
00507 
00508         if(cache_result == PTCACHE_READ_EXACT || cache_result == PTCACHE_READ_INTERPOLATED) {
00509                 implicit_set_positions(clmd);
00510                 cloth_to_object (ob, clmd, result);
00511 
00512                 BKE_ptcache_validate(cache, framenr);
00513 
00514                 if(cache_result == PTCACHE_READ_INTERPOLATED && cache->flag & PTCACHE_REDO_NEEDED)
00515                         BKE_ptcache_write(&pid, framenr);
00516 
00517                 return result;
00518         }
00519         else if(cache_result==PTCACHE_READ_OLD) {
00520                 implicit_set_positions(clmd);
00521         }
00522         else if( /*ob->id.lib ||*/ (cache->flag & PTCACHE_BAKED)) { /* 2.4x disabled lib, but this can be used in some cases, testing further - campbell */
00523                 /* if baked and nothing in cache, do nothing */
00524                 BKE_ptcache_invalidate(cache);
00525                 return result;
00526         }
00527 
00528         /* if on second frame, write cache for first frame */
00529         if(cache->simframe == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact==0))
00530                 BKE_ptcache_write(&pid, startframe);
00531 
00532         clmd->sim_parms->timescale *= framenr - cache->simframe;
00533 
00534         /* do simulation */
00535         BKE_ptcache_validate(cache, framenr);
00536 
00537         if(!do_step_cloth(ob, clmd, dm, framenr)) {
00538                 BKE_ptcache_invalidate(cache);
00539         }
00540         else
00541                 BKE_ptcache_write(&pid, framenr);
00542 
00543         cloth_to_object (ob, clmd, result);
00544 
00545         return result;
00546 }
00547 
00548 /* frees all */
00549 void cloth_free_modifier(ClothModifierData *clmd )
00550 {
00551         Cloth   *cloth = NULL;
00552         
00553         if ( !clmd )
00554                 return;
00555 
00556         cloth = clmd->clothObject;
00557 
00558         
00559         if ( cloth )
00560         {       
00561                 // If our solver provides a free function, call it
00562                 if ( solvers [clmd->sim_parms->solver_type].free )
00563                 {
00564                         solvers [clmd->sim_parms->solver_type].free ( clmd );
00565                 }
00566 
00567                 // Free the verts.
00568                 if ( cloth->verts != NULL )
00569                         MEM_freeN ( cloth->verts );
00570 
00571                 cloth->verts = NULL;
00572                 cloth->numverts = 0;
00573 
00574                 // Free the springs.
00575                 if ( cloth->springs != NULL )
00576                 {
00577                         LinkNode *search = cloth->springs;
00578                         while(search)
00579                         {
00580                                 ClothSpring *spring = search->link;
00581                                                 
00582                                 MEM_freeN ( spring );
00583                                 search = search->next;
00584                         }
00585                         BLI_linklist_free(cloth->springs, NULL);
00586                 
00587                         cloth->springs = NULL;
00588                 }
00589 
00590                 cloth->springs = NULL;
00591                 cloth->numsprings = 0;
00592 
00593                 // free BVH collision tree
00594                 if ( cloth->bvhtree )
00595                         BLI_bvhtree_free ( cloth->bvhtree );
00596                 
00597                 if ( cloth->bvhselftree )
00598                         BLI_bvhtree_free ( cloth->bvhselftree );
00599 
00600                 // we save our faces for collision objects
00601                 if ( cloth->mfaces )
00602                         MEM_freeN ( cloth->mfaces );
00603                 
00604                 if(cloth->edgehash)
00605                         BLI_edgehash_free ( cloth->edgehash, NULL );
00606                 
00607                 
00608                 /*
00609                 if(clmd->clothObject->facemarks)
00610                 MEM_freeN(clmd->clothObject->facemarks);
00611                 */
00612                 MEM_freeN ( cloth );
00613                 clmd->clothObject = NULL;
00614         }
00615 }
00616 
00617 /* frees all */
00618 void cloth_free_modifier_extern ( ClothModifierData *clmd )
00619 {
00620         Cloth   *cloth = NULL;
00621         if(G.rt > 0)
00622                 printf("cloth_free_modifier_extern\n");
00623         
00624         if ( !clmd )
00625                 return;
00626 
00627         cloth = clmd->clothObject;
00628         
00629         if ( cloth )
00630         {       
00631                 if(G.rt > 0)
00632                         printf("cloth_free_modifier_extern in\n");
00633                 
00634                 // If our solver provides a free function, call it
00635                 if ( solvers [clmd->sim_parms->solver_type].free )
00636                 {
00637                         solvers [clmd->sim_parms->solver_type].free ( clmd );
00638                 }
00639 
00640                 // Free the verts.
00641                 if ( cloth->verts != NULL )
00642                         MEM_freeN ( cloth->verts );
00643 
00644                 cloth->verts = NULL;
00645                 cloth->numverts = 0;
00646 
00647                 // Free the springs.
00648                 if ( cloth->springs != NULL )
00649                 {
00650                         LinkNode *search = cloth->springs;
00651                         while(search)
00652                         {
00653                                 ClothSpring *spring = search->link;
00654                                                 
00655                                 MEM_freeN ( spring );
00656                                 search = search->next;
00657                         }
00658                         BLI_linklist_free(cloth->springs, NULL);
00659                 
00660                         cloth->springs = NULL;
00661                 }
00662 
00663                 cloth->springs = NULL;
00664                 cloth->numsprings = 0;
00665 
00666                 // free BVH collision tree
00667                 if ( cloth->bvhtree )
00668                         BLI_bvhtree_free ( cloth->bvhtree );
00669                 
00670                 if ( cloth->bvhselftree )
00671                         BLI_bvhtree_free ( cloth->bvhselftree );
00672 
00673                 // we save our faces for collision objects
00674                 if ( cloth->mfaces )
00675                         MEM_freeN ( cloth->mfaces );
00676                 
00677                 if(cloth->edgehash)
00678                         BLI_edgehash_free ( cloth->edgehash, NULL );
00679                 
00680                 
00681                 /*
00682                 if(clmd->clothObject->facemarks)
00683                 MEM_freeN(clmd->clothObject->facemarks);
00684                 */
00685                 MEM_freeN ( cloth );
00686                 clmd->clothObject = NULL;
00687         }
00688 }
00689 
00690 /******************************************************************************
00691 *
00692 * Internal functions.
00693 *
00694 ******************************************************************************/
00695 
00700 static void cloth_to_object (Object *ob,  ClothModifierData *clmd, DerivedMesh *dm)
00701 {
00702         unsigned int    i = 0;
00703         MVert *mvert = NULL;
00704         unsigned int numverts;
00705         Cloth *cloth = clmd->clothObject;
00706 
00707         if (clmd->clothObject) {
00708                 /* inverse matrix is not uptodate... */
00709                 invert_m4_m4(ob->imat, ob->obmat);
00710 
00711                 mvert = CDDM_get_verts(dm);
00712                 numverts = dm->getNumVerts(dm);
00713 
00714                 for (i = 0; i < numverts; i++)
00715                 {
00716                         VECCOPY (mvert[i].co, cloth->verts[i].x);
00717                         mul_m4_v3(ob->imat, mvert[i].co);       /* cloth is in global coords */
00718                 }
00719         }
00720 }
00721 
00722 
00723 int cloth_uses_vgroup(ClothModifierData *clmd)
00724 {
00725         return (((clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SCALING ) || 
00726                 (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL )) && 
00727                 ((clmd->sim_parms->vgroup_mass>0) || 
00728                 (clmd->sim_parms->vgroup_struct>0)||
00729                 (clmd->sim_parms->vgroup_bend>0)));
00730 }
00731 
00736 /* can be optimized to do all groups in one loop */
00737 static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm )
00738 {
00739         int i = 0;
00740         int j = 0;
00741         MDeformVert *dvert = NULL;
00742         Cloth *clothObj = NULL;
00743         int numverts;
00744         float goalfac = 0;
00745         ClothVertex *verts = NULL;
00746 
00747         if (!clmd || !dm) return;
00748 
00749         clothObj = clmd->clothObject;
00750 
00751         numverts = dm->getNumVerts ( dm );
00752 
00753         verts = clothObj->verts;
00754         
00755         if (cloth_uses_vgroup(clmd))
00756         {
00757                 for ( i = 0; i < numverts; i++, verts++ )
00758                 {       
00759                         dvert = dm->getVertData ( dm, i, CD_MDEFORMVERT );
00760                         if ( dvert )
00761                         {
00762                                 for ( j = 0; j < dvert->totweight; j++ )
00763                                 {
00764                                         if (( dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_mass-1)) && (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL ))
00765                                         {
00766                                                 verts->goal = dvert->dw [j].weight;
00767                                                 goalfac= 1.0f;
00768                                                 
00769                                                 /*
00770                                                 // Kicking goal factor to simplify things...who uses that anyway?
00771                                                 // ABS ( clmd->sim_parms->maxgoal - clmd->sim_parms->mingoal );
00772                                                 */
00773                                                 
00774                                                 verts->goal  = ( float ) pow ( verts->goal , 4.0f );
00775                                                 if ( verts->goal >=SOFTGOALSNAP )
00776                                                 {
00777                                                          verts->flags |= CLOTH_VERT_FLAG_PINNED;
00778                                                 }
00779                                         }
00780                                         
00781                                         if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SCALING )
00782                                         {
00783                                                 if( dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_struct-1))
00784                                                 {
00785                                                         verts->struct_stiff = dvert->dw [j].weight;
00786                                                         verts->shear_stiff = dvert->dw [j].weight;
00787                                                 }
00788                                                 
00789                                                 if( dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_bend-1))
00790                                                 {
00791                                                         verts->bend_stiff = dvert->dw [j].weight;
00792                                                 }
00793                                         }
00794                                         /*
00795                                         // for later
00796                                         if( dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_weight-1))
00797                                         {
00798                                                 verts->mass = dvert->dw [j].weight;
00799                                         }
00800                                         */
00801                                 }
00802                         }
00803                 }
00804         }
00805 }
00806 
00807 static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *dm, float UNUSED(framenr), int first)
00808 {
00809         int i = 0;
00810         MVert *mvert = NULL;
00811         ClothVertex *verts = NULL;
00812         float (*shapekey_rest)[3]= NULL;
00813         float tnull[3] = {0,0,0};
00814         Cloth *cloth = NULL;
00815         float maxdist = 0;
00816 
00817         // If we have a clothObject, free it. 
00818         if ( clmd->clothObject != NULL )
00819         {
00820                 cloth_free_modifier ( clmd );
00821                 if(G.rt > 0)
00822                         printf("cloth_free_modifier cloth_from_object\n");
00823         }
00824 
00825         // Allocate a new cloth object.
00826         clmd->clothObject = MEM_callocN ( sizeof ( Cloth ), "cloth" );
00827         if ( clmd->clothObject )
00828         {
00829                 clmd->clothObject->old_solver_type = 255;
00830                 // clmd->clothObject->old_collision_type = 255;
00831                 cloth = clmd->clothObject;
00832                 clmd->clothObject->edgehash = NULL;
00833         }
00834         else if ( !clmd->clothObject )
00835         {
00836                 modifier_setError ( & ( clmd->modifier ), "Out of memory on allocating clmd->clothObject." );
00837                 return 0;
00838         }
00839 
00840         // mesh input objects need DerivedMesh
00841         if ( !dm )
00842                 return 0;
00843 
00844         cloth_from_mesh ( clmd, dm );
00845 
00846         // create springs 
00847         clmd->clothObject->springs = NULL;
00848         clmd->clothObject->numsprings = -1;
00849         
00850         if( clmd->sim_parms->shapekey_rest )
00851                 shapekey_rest = dm->getVertDataArray ( dm, CD_CLOTH_ORCO );
00852 
00853         mvert = dm->getVertArray ( dm );
00854 
00855         verts = clmd->clothObject->verts;
00856 
00857         // set initial values
00858         for ( i = 0; i < dm->getNumVerts(dm); i++, verts++ )
00859         {
00860                 if(first)
00861                 {
00862                         copy_v3_v3( verts->x, mvert[i].co );
00863 
00864                         mul_m4_v3( ob->obmat, verts->x );
00865 
00866                         if( shapekey_rest ) {
00867                                 verts->xrest= shapekey_rest[i];
00868                                 mul_m4_v3( ob->obmat, verts->xrest );
00869                         }
00870                         else
00871                                 verts->xrest = verts->x;
00872                 }
00873                 
00874                 /* no GUI interface yet */
00875                 verts->mass = clmd->sim_parms->mass; 
00876                 verts->impulse_count = 0;
00877 
00878                 if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL )
00879                         verts->goal= clmd->sim_parms->defgoal;
00880                 else
00881                         verts->goal= 0.0f;
00882 
00883                 verts->flags = 0;
00884                 VECCOPY ( verts->xold, verts->x );
00885                 VECCOPY ( verts->xconst, verts->x );
00886                 VECCOPY ( verts->txold, verts->x );
00887                 VECCOPY ( verts->tx, verts->x );
00888                 mul_v3_fl( verts->v, 0.0f );
00889 
00890                 verts->impulse_count = 0;
00891                 VECCOPY ( verts->impulse, tnull );
00892         }
00893         
00894         // apply / set vertex groups
00895         // has to be happen before springs are build!
00896         cloth_apply_vgroup (clmd, dm);
00897 
00898         if ( !cloth_build_springs ( clmd, dm ) )
00899         {
00900                 cloth_free_modifier ( clmd );
00901                 modifier_setError ( & ( clmd->modifier ), "Can't build springs." );
00902                 printf("cloth_free_modifier cloth_build_springs\n");
00903                 return 0;
00904         }
00905         
00906         for ( i = 0; i < dm->getNumVerts(dm); i++)
00907         {
00908                 if((!(cloth->verts[i].flags & CLOTH_VERT_FLAG_PINNED)) && (cloth->verts[i].goal > ALMOST_ZERO))
00909                 {
00910                         cloth_add_spring (clmd, i, i, 0.0, CLOTH_SPRING_TYPE_GOAL);
00911                 }
00912         }
00913         
00914         // init our solver
00915         if ( solvers [clmd->sim_parms->solver_type].init ) {
00916                 solvers [clmd->sim_parms->solver_type].init ( ob, clmd );
00917         }
00918         
00919         if(!first)
00920                 implicit_set_positions(clmd);
00921 
00922         clmd->clothObject->bvhtree = bvhtree_build_from_cloth ( clmd, MAX2(clmd->coll_parms->epsilon, clmd->coll_parms->distance_repel) );
00923         
00924         for(i = 0; i < dm->getNumVerts(dm); i++)
00925         {
00926                 maxdist = MAX2(maxdist, clmd->coll_parms->selfepsilon* ( cloth->verts[i].avg_spring_len*2.0));
00927         }
00928         
00929         clmd->clothObject->bvhselftree = bvhselftree_build_from_cloth ( clmd, maxdist );
00930 
00931         return 1;
00932 }
00933 
00934 static void cloth_from_mesh ( ClothModifierData *clmd, DerivedMesh *dm )
00935 {
00936         unsigned int numverts = dm->getNumVerts ( dm );
00937         unsigned int numfaces = dm->getNumFaces ( dm );
00938         MFace *mface = dm->getFaceArray( dm );
00939         unsigned int i = 0;
00940 
00941         /* Allocate our vertices. */
00942         clmd->clothObject->numverts = numverts;
00943         clmd->clothObject->verts = MEM_callocN ( sizeof ( ClothVertex ) * clmd->clothObject->numverts, "clothVertex" );
00944         if ( clmd->clothObject->verts == NULL )
00945         {
00946                 cloth_free_modifier ( clmd );
00947                 modifier_setError ( & ( clmd->modifier ), "Out of memory on allocating clmd->clothObject->verts." );
00948                 printf("cloth_free_modifier clmd->clothObject->verts\n");
00949                 return;
00950         }
00951 
00952         // save face information
00953         clmd->clothObject->numfaces = numfaces;
00954         clmd->clothObject->mfaces = MEM_callocN ( sizeof ( MFace ) * clmd->clothObject->numfaces, "clothMFaces" );
00955         if ( clmd->clothObject->mfaces == NULL )
00956         {
00957                 cloth_free_modifier ( clmd );
00958                 modifier_setError ( & ( clmd->modifier ), "Out of memory on allocating clmd->clothObject->mfaces." );
00959                 printf("cloth_free_modifier clmd->clothObject->mfaces\n");
00960                 return;
00961         }
00962         for ( i = 0; i < numfaces; i++ )
00963                 memcpy ( &clmd->clothObject->mfaces[i], &mface[i], sizeof ( MFace ) );
00964 
00965         /* Free the springs since they can't be correct if the vertices
00966         * changed.
00967         */
00968         if ( clmd->clothObject->springs != NULL )
00969                 MEM_freeN ( clmd->clothObject->springs );
00970 
00971 }
00972 
00973 /***************************************************************************************
00974 * SPRING NETWORK BUILDING IMPLEMENTATION BEGIN
00975 ***************************************************************************************/
00976 
00977 // be carefull: implicit solver has to be resettet when using this one!
00978 // --> only for implicit handling of this spring!
00979 int cloth_add_spring ( ClothModifierData *clmd, unsigned int indexA, unsigned int indexB, float restlength, int spring_type)
00980 {
00981         Cloth *cloth = clmd->clothObject;
00982         ClothSpring *spring = NULL;
00983         
00984         if(cloth)
00985         {
00986                 // TODO: look if this spring is already there
00987                 
00988                 spring = ( ClothSpring * ) MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" );
00989                 
00990                 if(!spring)
00991                         return 0;
00992                 
00993                 spring->ij = indexA;
00994                 spring->kl = indexB;
00995                 spring->restlen =  restlength;
00996                 spring->type = spring_type;
00997                 spring->flags = 0;
00998                 spring->stiffness = 0;
00999                 
01000                 cloth->numsprings++;
01001         
01002                 BLI_linklist_prepend ( &cloth->springs, spring );
01003                 
01004                 return 1;
01005         }
01006         return 0;
01007 }
01008 
01009 static void cloth_free_errorsprings(Cloth *cloth, EdgeHash *UNUSED(edgehash), LinkNode **edgelist)
01010 {
01011         unsigned int i = 0;
01012         
01013         if ( cloth->springs != NULL )
01014         {
01015                 LinkNode *search = cloth->springs;
01016                 while(search)
01017                 {
01018                         ClothSpring *spring = search->link;
01019                                                 
01020                         MEM_freeN ( spring );
01021                         search = search->next;
01022                 }
01023                 BLI_linklist_free(cloth->springs, NULL);
01024                 
01025                 cloth->springs = NULL;
01026         }
01027         
01028         if(edgelist)
01029         {
01030                 for ( i = 0; i < cloth->numverts; i++ )
01031                 {
01032                         BLI_linklist_free ( edgelist[i],NULL );
01033                 }
01034 
01035                 MEM_freeN ( edgelist );
01036         }
01037         
01038         if(cloth->edgehash)
01039                 BLI_edgehash_free ( cloth->edgehash, NULL );
01040 }
01041 
01042 static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
01043 {
01044         Cloth *cloth = clmd->clothObject;
01045         ClothSpring *spring = NULL, *tspring = NULL, *tspring2 = NULL;
01046         unsigned int struct_springs = 0, shear_springs=0, bend_springs = 0;
01047         unsigned int i = 0;
01048         unsigned int numverts = (unsigned int)dm->getNumVerts ( dm );
01049         unsigned int numedges = (unsigned int)dm->getNumEdges ( dm );
01050         unsigned int numfaces = (unsigned int)dm->getNumFaces ( dm );
01051         MEdge *medge = dm->getEdgeArray ( dm );
01052         MFace *mface = dm->getFaceArray ( dm );
01053         int index2 = 0; // our second vertex index
01054         LinkNode **edgelist = NULL;
01055         EdgeHash *edgehash = NULL;
01056         LinkNode *search = NULL, *search2 = NULL;
01057         float temp[3];
01058         
01059         // error handling
01060         if ( numedges==0 )
01061                 return 0;
01062 
01063         cloth->springs = NULL;
01064 
01065         edgelist = MEM_callocN ( sizeof ( LinkNode * ) * numverts, "cloth_edgelist_alloc" );
01066         
01067         if(!edgelist)
01068                 return 0;
01069         
01070         for ( i = 0; i < numverts; i++ )
01071         {
01072                 edgelist[i] = NULL;
01073         }
01074 
01075         if ( cloth->springs )
01076                 MEM_freeN ( cloth->springs );
01077 
01078         // create spring network hash
01079         edgehash = BLI_edgehash_new();
01080 
01081         // structural springs
01082         for ( i = 0; i < numedges; i++ )
01083         {
01084                 spring = ( ClothSpring * ) MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" );
01085 
01086                 if ( spring )
01087                 {
01088                         spring->ij = MIN2(medge[i].v1, medge[i].v2);
01089                         spring->kl = MAX2(medge[i].v2, medge[i].v1);
01090                         VECSUB ( temp, cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest );
01091                         spring->restlen =  sqrt ( INPR ( temp, temp ) );
01092                         clmd->sim_parms->avg_spring_len += spring->restlen;
01093                         cloth->verts[spring->ij].avg_spring_len += spring->restlen;
01094                         cloth->verts[spring->kl].avg_spring_len += spring->restlen;
01095                         cloth->verts[spring->ij].spring_count++;
01096                         cloth->verts[spring->kl].spring_count++;
01097                         spring->type = CLOTH_SPRING_TYPE_STRUCTURAL;
01098                         spring->flags = 0;
01099                         spring->stiffness = (cloth->verts[spring->kl].struct_stiff + cloth->verts[spring->ij].struct_stiff) / 2.0;
01100                         struct_springs++;
01101                         
01102                         BLI_linklist_prepend ( &cloth->springs, spring );
01103                 }
01104                 else
01105                 {
01106                         cloth_free_errorsprings(cloth, edgehash, edgelist);
01107                         return 0;
01108                 }
01109         }
01110         
01111         if(struct_springs > 0)
01112                 clmd->sim_parms->avg_spring_len /= struct_springs;
01113         
01114         for(i = 0; i < numverts; i++)
01115         {
01116                 cloth->verts[i].avg_spring_len = cloth->verts[i].avg_spring_len * 0.49 / ((float)cloth->verts[i].spring_count);
01117         }
01118         
01119         // shear springs
01120         for ( i = 0; i < numfaces; i++ )
01121         {
01122                 // triangle faces already have shear springs due to structural geometry
01123                 if ( !mface[i].v4 )
01124                         continue; 
01125                 
01126                 spring = ( ClothSpring *) MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" );
01127                 
01128                 if(!spring)
01129                 {
01130                         cloth_free_errorsprings(cloth, edgehash, edgelist);
01131                         return 0;
01132                 }
01133 
01134                 spring->ij = MIN2(mface[i].v1, mface[i].v3);
01135                 spring->kl = MAX2(mface[i].v3, mface[i].v1);
01136                 VECSUB ( temp, cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest );
01137                 spring->restlen =  sqrt ( INPR ( temp, temp ) );
01138                 spring->type = CLOTH_SPRING_TYPE_SHEAR;
01139                 spring->stiffness = (cloth->verts[spring->kl].shear_stiff + cloth->verts[spring->ij].shear_stiff) / 2.0;
01140 
01141                 BLI_linklist_append ( &edgelist[spring->ij], spring );
01142                 BLI_linklist_append ( &edgelist[spring->kl], spring );
01143                 shear_springs++;
01144 
01145                 BLI_linklist_prepend ( &cloth->springs, spring );
01146 
01147                 
01148                 // if ( mface[i].v4 ) --> Quad face
01149                 spring = ( ClothSpring * ) MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" );
01150                 
01151                 if(!spring)
01152                 {
01153                         cloth_free_errorsprings(cloth, edgehash, edgelist);
01154                         return 0;
01155                 }
01156 
01157                 spring->ij = MIN2(mface[i].v2, mface[i].v4);
01158                 spring->kl = MAX2(mface[i].v4, mface[i].v2);
01159                 VECSUB ( temp, cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest );
01160                 spring->restlen =  sqrt ( INPR ( temp, temp ) );
01161                 spring->type = CLOTH_SPRING_TYPE_SHEAR;
01162                 spring->stiffness = (cloth->verts[spring->kl].shear_stiff + cloth->verts[spring->ij].shear_stiff) / 2.0;
01163 
01164                 BLI_linklist_append ( &edgelist[spring->ij], spring );
01165                 BLI_linklist_append ( &edgelist[spring->kl], spring );
01166                 shear_springs++;
01167 
01168                 BLI_linklist_prepend ( &cloth->springs, spring );
01169         }
01170         
01171         if(numfaces) {
01172                 // bending springs
01173                 search2 = cloth->springs;
01174                 for ( i = struct_springs; i < struct_springs+shear_springs; i++ )
01175                 {
01176                         if ( !search2 )
01177                                 break;
01178 
01179                         tspring2 = search2->link;
01180                         search = edgelist[tspring2->kl];
01181                         while ( search )
01182                         {
01183                                 tspring = search->link;
01184                                 index2 = ( ( tspring->ij==tspring2->kl ) ? ( tspring->kl ) : ( tspring->ij ) );
01185                                 
01186                                 // check for existing spring
01187                                 // check also if startpoint is equal to endpoint
01188                                 if ( !BLI_edgehash_haskey ( edgehash, MIN2(tspring2->ij, index2), MAX2(tspring2->ij, index2) )
01189                                 && ( index2!=tspring2->ij ) )
01190                                 {
01191                                         spring = ( ClothSpring * ) MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" );
01192                                         
01193                                         if(!spring)
01194                                         {
01195                                                 cloth_free_errorsprings(cloth, edgehash, edgelist);
01196                                                 return 0;
01197                                         }
01198 
01199                                         spring->ij = MIN2(tspring2->ij, index2);
01200                                         spring->kl = MAX2(tspring2->ij, index2);
01201                                         VECSUB ( temp, cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest );
01202                                         spring->restlen =  sqrt ( INPR ( temp, temp ) );
01203                                         spring->type = CLOTH_SPRING_TYPE_BENDING;
01204                                         spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0;
01205                                         BLI_edgehash_insert ( edgehash, spring->ij, spring->kl, NULL );
01206                                         bend_springs++;
01207 
01208                                         BLI_linklist_prepend ( &cloth->springs, spring );
01209                                 }
01210                                 search = search->next;
01211                         }
01212                         search2 = search2->next;
01213                 }
01214         }
01215         else if(struct_springs > 2) {
01216                 /* bending springs for hair strands */
01217                 /* The current algorightm only goes through the edges in order of the mesh edges list   */
01218                 /* and makes springs between the outer vert of edges sharing a vertice. This works just */
01219                 /* fine for hair, but not for user generated string meshes. This could/should be later  */
01220                 /* extended to work with non-ordered edges so that it can be used for general "rope             */
01221                 /* dynamics" without the need for the vertices or edges to be ordered through the length*/
01222                 /* of the strands. -jahka */
01223                 search = cloth->springs;
01224                 search2 = search->next;
01225                 while(search && search2)
01226                 {
01227                         tspring = search->link;
01228                         tspring2 = search2->link;
01229 
01230                         if(tspring->ij == tspring2->kl) {
01231                                 spring = ( ClothSpring * ) MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" );
01232                                 
01233                                 if(!spring)
01234                                 {
01235                                         cloth_free_errorsprings(cloth, edgehash, edgelist);
01236                                         return 0;
01237                                 }
01238 
01239                                 spring->ij = tspring2->ij;
01240                                 spring->kl = tspring->kl;
01241                                 VECSUB ( temp, cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest );
01242                                 spring->restlen =  sqrt ( INPR ( temp, temp ) );
01243                                 spring->type = CLOTH_SPRING_TYPE_BENDING;
01244                                 spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0;
01245                                 bend_springs++;
01246 
01247                                 BLI_linklist_prepend ( &cloth->springs, spring );
01248                         }
01249                         
01250                         search = search->next;
01251                         search2 = search2->next;
01252                 }
01253         }
01254         
01255         /* insert other near springs in edgehash AFTER bending springs are calculated (for selfcolls) */
01256         for ( i = 0; i < numedges; i++ ) // struct springs
01257                 BLI_edgehash_insert ( edgehash, MIN2(medge[i].v1, medge[i].v2), MAX2(medge[i].v2, medge[i].v1), NULL );
01258         
01259         for ( i = 0; i < numfaces; i++ ) // edge springs
01260         {
01261                 if(mface[i].v4)
01262                 {
01263                         BLI_edgehash_insert ( edgehash, MIN2(mface[i].v1, mface[i].v3), MAX2(mface[i].v3, mface[i].v1), NULL );
01264                         
01265                         BLI_edgehash_insert ( edgehash, MIN2(mface[i].v2, mface[i].v4), MAX2(mface[i].v2, mface[i].v4), NULL );
01266                 }
01267         }
01268         
01269         
01270         cloth->numsprings = struct_springs + shear_springs + bend_springs;
01271         
01272         if ( edgelist )
01273         {
01274                 for ( i = 0; i < numverts; i++ )
01275                 {
01276                         BLI_linklist_free ( edgelist[i],NULL );
01277                 }
01278         
01279                 MEM_freeN ( edgelist );
01280         }
01281         
01282         cloth->edgehash = edgehash;
01283         
01284         if(G.rt>0)
01285                 printf("avg_len: %f\n",clmd->sim_parms->avg_spring_len);
01286 
01287         return 1;
01288 
01289 } /* cloth_build_springs */
01290 /***************************************************************************************
01291 * SPRING NETWORK BUILDING IMPLEMENTATION END
01292 ***************************************************************************************/
01293