/** * Reads the contents of a text file and returns the lines in a linked list. */ LinkNode *BLI_file_read_as_lines(const char *name) { FILE *fp = BLI_fopen(name, "r"); LinkNodePair lines = {NULL, NULL}; char *buf; size_t size; if (!fp) return NULL; fseek(fp, 0, SEEK_END); size = (size_t)ftell(fp); fseek(fp, 0, SEEK_SET); if (UNLIKELY(size == (size_t)-1)) { fclose(fp); return NULL; } buf = MEM_mallocN(size, "file_as_lines"); if (buf) { size_t i, last = 0; /* * size = because on win32 reading * all the bytes in the file will return * less bytes because of crnl changes. */ size = fread(buf, 1, size, fp); for (i = 0; i <= size; i++) { if (i == size || buf[i] == '\n') { char *line = BLI_strdupn(&buf[last], i - last); BLI_linklist_append(&lines, line); /* faster to build singly-linked list in reverse order */ /* alternatively, could process buffer in reverse order so * list ends up right way round to start with */ last = i + 1; } } MEM_freeN(buf); } fclose(fp); return lines.list; }
static int create_navmesh_exec(bContext *C, wmOperator *op) { Scene* scene= CTX_data_scene(C); LinkNode* obs= NULL; Base* navmeshBase= NULL; CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) { if (base->object->type == OB_MESH) { if (base->object->body_type==OB_BODY_TYPE_NAVMESH) { if (!navmeshBase || base == scene->basact) { navmeshBase= base; } } else { BLI_linklist_append(&obs, (void*)base->object); } } } CTX_DATA_END; if (obs) { struct recast_polyMesh *pmesh= NULL; struct recast_polyMeshDetail *dmesh= NULL; int nverts= 0, ntris= 0; int *tris= 0; float *verts= NULL; createVertsTrisData(C, obs, &nverts, &verts, &ntris, &tris); BLI_linklist_free(obs, NULL); buildNavMesh(&scene->gm.recastData, nverts, verts, ntris, tris, &pmesh, &dmesh); createRepresentation(C, pmesh, dmesh, navmeshBase); MEM_freeN(verts); MEM_freeN(tris); return OPERATOR_FINISHED; } else { BKE_report(op->reports, RPT_ERROR, "No mesh objects found"); return OPERATOR_CANCELLED; } }
/** * Reads the contents of a text file and returns the lines in a linked list. */ LinkNode *BLI_file_read_as_lines(const char *name) { FILE *fp = BLI_fopen(name, "r"); LinkNodePair lines = {NULL, NULL}; char *buf; size_t size; if (!fp) return NULL; fseek(fp, 0, SEEK_END); size = (size_t)ftell(fp); fseek(fp, 0, SEEK_SET); if (UNLIKELY(size == (size_t)-1)) { fclose(fp); return NULL; } buf = MEM_mallocN(size, "file_as_lines"); if (buf) { size_t i, last = 0; /* * size = because on win32 reading * all the bytes in the file will return * less bytes because of `CRNL` changes. */ size = fread(buf, 1, size, fp); for (i = 0; i <= size; i++) { if (i == size || buf[i] == '\n') { char *line = BLI_strdupn(&buf[last], i - last); BLI_linklist_append(&lines, line); last = i + 1; } } MEM_freeN(buf); } fclose(fp); return lines.list; }
static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm ) { Cloth *cloth = clmd->clothObject; ClothSpring *spring = NULL, *tspring = NULL, *tspring2 = NULL; unsigned int struct_springs = 0, shear_springs=0, bend_springs = 0; unsigned int i = 0; unsigned int numverts = (unsigned int)dm->getNumVerts ( dm ); unsigned int numedges = (unsigned int)dm->getNumEdges ( dm ); unsigned int numfaces = (unsigned int)dm->getNumFaces ( dm ); MEdge *medge = dm->getEdgeArray ( dm ); MFace *mface = dm->getFaceArray ( dm ); int index2 = 0; // our second vertex index LinkNode **edgelist = NULL; EdgeHash *edgehash = NULL; LinkNode *search = NULL, *search2 = NULL; // error handling if ( numedges==0 ) return 0; cloth->springs = NULL; edgelist = MEM_callocN ( sizeof ( LinkNode * ) * numverts, "cloth_edgelist_alloc" ); if(!edgelist) return 0; for ( i = 0; i < numverts; i++ ) { edgelist[i] = NULL; } if ( cloth->springs ) MEM_freeN ( cloth->springs ); // create spring network hash edgehash = BLI_edgehash_new(); // structural springs for ( i = 0; i < numedges; i++ ) { spring = ( ClothSpring * ) MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); if ( spring ) { spring->ij = MIN2(medge[i].v1, medge[i].v2); spring->kl = MAX2(medge[i].v2, medge[i].v1); spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest); clmd->sim_parms->avg_spring_len += spring->restlen; cloth->verts[spring->ij].avg_spring_len += spring->restlen; cloth->verts[spring->kl].avg_spring_len += spring->restlen; cloth->verts[spring->ij].spring_count++; cloth->verts[spring->kl].spring_count++; spring->type = CLOTH_SPRING_TYPE_STRUCTURAL; spring->flags = 0; spring->stiffness = (cloth->verts[spring->kl].struct_stiff + cloth->verts[spring->ij].struct_stiff) / 2.0f; struct_springs++; BLI_linklist_prepend ( &cloth->springs, spring ); } else { cloth_free_errorsprings(cloth, edgehash, edgelist); return 0; } } if(struct_springs > 0) clmd->sim_parms->avg_spring_len /= struct_springs; for(i = 0; i < numverts; i++) { cloth->verts[i].avg_spring_len = cloth->verts[i].avg_spring_len * 0.49f / ((float)cloth->verts[i].spring_count); } // shear springs for ( i = 0; i < numfaces; i++ ) { // triangle faces already have shear springs due to structural geometry if ( !mface[i].v4 ) continue; spring = ( ClothSpring *) MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); if(!spring) { cloth_free_errorsprings(cloth, edgehash, edgelist); return 0; } spring->ij = MIN2(mface[i].v1, mface[i].v3); spring->kl = MAX2(mface[i].v3, mface[i].v1); spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest); spring->type = CLOTH_SPRING_TYPE_SHEAR; spring->stiffness = (cloth->verts[spring->kl].shear_stiff + cloth->verts[spring->ij].shear_stiff) / 2.0f; BLI_linklist_append ( &edgelist[spring->ij], spring ); BLI_linklist_append ( &edgelist[spring->kl], spring ); shear_springs++; BLI_linklist_prepend ( &cloth->springs, spring ); // if ( mface[i].v4 ) --> Quad face spring = ( ClothSpring * ) MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); if(!spring) { cloth_free_errorsprings(cloth, edgehash, edgelist); return 0; } spring->ij = MIN2(mface[i].v2, mface[i].v4); spring->kl = MAX2(mface[i].v4, mface[i].v2); spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest); spring->type = CLOTH_SPRING_TYPE_SHEAR; spring->stiffness = (cloth->verts[spring->kl].shear_stiff + cloth->verts[spring->ij].shear_stiff) / 2.0; BLI_linklist_append ( &edgelist[spring->ij], spring ); BLI_linklist_append ( &edgelist[spring->kl], spring ); shear_springs++; BLI_linklist_prepend ( &cloth->springs, spring ); } if(numfaces) { // bending springs search2 = cloth->springs; for ( i = struct_springs; i < struct_springs+shear_springs; i++ ) { if ( !search2 ) break; tspring2 = search2->link; search = edgelist[tspring2->kl]; while ( search ) { tspring = search->link; index2 = ( ( tspring->ij==tspring2->kl ) ? ( tspring->kl ) : ( tspring->ij ) ); // check for existing spring // check also if startpoint is equal to endpoint if ( !BLI_edgehash_haskey ( edgehash, MIN2(tspring2->ij, index2), MAX2(tspring2->ij, index2) ) && ( index2!=tspring2->ij ) ) { spring = ( ClothSpring * ) MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); if(!spring) { cloth_free_errorsprings(cloth, edgehash, edgelist); return 0; } spring->ij = MIN2(tspring2->ij, index2); spring->kl = MAX2(tspring2->ij, index2); spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest); spring->type = CLOTH_SPRING_TYPE_BENDING; spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f; BLI_edgehash_insert ( edgehash, spring->ij, spring->kl, NULL ); bend_springs++; BLI_linklist_prepend ( &cloth->springs, spring ); } search = search->next; } search2 = search2->next; } } else if(struct_springs > 2) { /* bending springs for hair strands */ /* The current algorightm only goes through the edges in order of the mesh edges list */ /* and makes springs between the outer vert of edges sharing a vertice. This works just */ /* fine for hair, but not for user generated string meshes. This could/should be later */ /* extended to work with non-ordered edges so that it can be used for general "rope */ /* dynamics" without the need for the vertices or edges to be ordered through the length*/ /* of the strands. -jahka */ search = cloth->springs; search2 = search->next; while(search && search2) { tspring = search->link; tspring2 = search2->link; if(tspring->ij == tspring2->kl) { spring = ( ClothSpring * ) MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); if(!spring) { cloth_free_errorsprings(cloth, edgehash, edgelist); return 0; } spring->ij = tspring2->ij; spring->kl = tspring->kl; spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest); spring->type = CLOTH_SPRING_TYPE_BENDING; spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f; bend_springs++; BLI_linklist_prepend ( &cloth->springs, spring ); } search = search->next; search2 = search2->next; } } /* insert other near springs in edgehash AFTER bending springs are calculated (for selfcolls) */ for ( i = 0; i < numedges; i++ ) // struct springs BLI_edgehash_insert ( edgehash, MIN2(medge[i].v1, medge[i].v2), MAX2(medge[i].v2, medge[i].v1), NULL ); for ( i = 0; i < numfaces; i++ ) // edge springs { if(mface[i].v4) { BLI_edgehash_insert ( edgehash, MIN2(mface[i].v1, mface[i].v3), MAX2(mface[i].v3, mface[i].v1), NULL ); BLI_edgehash_insert ( edgehash, MIN2(mface[i].v2, mface[i].v4), MAX2(mface[i].v2, mface[i].v4), NULL ); } } cloth->numsprings = struct_springs + shear_springs + bend_springs; if ( edgelist ) { for ( i = 0; i < numverts; i++ ) { BLI_linklist_free ( edgelist[i],NULL ); } MEM_freeN ( edgelist ); } cloth->edgehash = edgehash; if(G.rt>0) printf("avg_len: %f\n",clmd->sim_parms->avg_spring_len); return 1; } /* cloth_build_springs */
static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm ) { Cloth *cloth = clmd->clothObject; ClothSpring *spring = NULL, *tspring = NULL, *tspring2 = NULL; unsigned int struct_springs = 0, shear_springs=0, bend_springs = 0; unsigned int i = 0; unsigned int numverts = (unsigned int)dm->getNumVerts (dm); unsigned int numedges = (unsigned int)dm->getNumEdges (dm); unsigned int numfaces = (unsigned int)dm->getNumTessFaces (dm); float shrink_factor; MEdge *medge = dm->getEdgeArray (dm); MFace *mface = dm->getTessFaceArray (dm); int index2 = 0; // our second vertex index LinkNode **edgelist = NULL; EdgeSet *edgeset = NULL; LinkNode *search = NULL, *search2 = NULL; // error handling if ( numedges==0 ) return 0; /* NOTE: handling ownership of springs and edgeset is quite sloppy * currently they are never initialized but assert just to be sure */ BLI_assert(cloth->springs == NULL); BLI_assert(cloth->edgeset == NULL); cloth->springs = NULL; cloth->edgeset = NULL; edgelist = MEM_callocN ( sizeof (LinkNode *) * numverts, "cloth_edgelist_alloc" ); if (!edgelist) return 0; // structural springs for ( i = 0; i < numedges; i++ ) { spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); if ( spring ) { spring_verts_ordered_set(spring, medge[i].v1, medge[i].v2); if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SEW && medge[i].flag & ME_LOOSEEDGE) { // handle sewing (loose edges will be pulled together) spring->restlen = 0.0f; spring->stiffness = 1.0f; spring->type = CLOTH_SPRING_TYPE_SEWING; } else { if (clmd->sim_parms->vgroup_shrink > 0) shrink_factor = 1.0f - ((cloth->verts[spring->ij].shrink_factor + cloth->verts[spring->kl].shrink_factor) / 2.0f); else shrink_factor = 1.0f - clmd->sim_parms->shrink_min; spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest) * shrink_factor; spring->stiffness = (cloth->verts[spring->kl].struct_stiff + cloth->verts[spring->ij].struct_stiff) / 2.0f; spring->type = CLOTH_SPRING_TYPE_STRUCTURAL; } clmd->sim_parms->avg_spring_len += spring->restlen; cloth->verts[spring->ij].avg_spring_len += spring->restlen; cloth->verts[spring->kl].avg_spring_len += spring->restlen; cloth->verts[spring->ij].spring_count++; cloth->verts[spring->kl].spring_count++; spring->flags = 0; struct_springs++; BLI_linklist_prepend ( &cloth->springs, spring ); } else { cloth_free_errorsprings(cloth, edgelist); return 0; } } if (struct_springs > 0) clmd->sim_parms->avg_spring_len /= struct_springs; for (i = 0; i < numverts; i++) { cloth->verts[i].avg_spring_len = cloth->verts[i].avg_spring_len * 0.49f / ((float)cloth->verts[i].spring_count); } // shear springs for ( i = 0; i < numfaces; i++ ) { // triangle faces already have shear springs due to structural geometry if ( !mface[i].v4 ) continue; spring = (ClothSpring *)MEM_callocN(sizeof(ClothSpring), "cloth spring"); if (!spring) { cloth_free_errorsprings(cloth, edgelist); return 0; } spring_verts_ordered_set(spring, mface[i].v1, mface[i].v3); if (clmd->sim_parms->vgroup_shrink > 0) shrink_factor = 1.0f - ((cloth->verts[spring->ij].shrink_factor + cloth->verts[spring->kl].shrink_factor) / 2.0f); else shrink_factor = 1.0f - clmd->sim_parms->shrink_min; spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest) * shrink_factor; spring->type = CLOTH_SPRING_TYPE_SHEAR; spring->stiffness = (cloth->verts[spring->kl].shear_stiff + cloth->verts[spring->ij].shear_stiff) / 2.0f; BLI_linklist_append ( &edgelist[spring->ij], spring ); BLI_linklist_append ( &edgelist[spring->kl], spring ); shear_springs++; BLI_linklist_prepend ( &cloth->springs, spring ); // if ( mface[i].v4 ) --> Quad face spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); if (!spring) { cloth_free_errorsprings(cloth, edgelist); return 0; } spring_verts_ordered_set(spring, mface[i].v2, mface[i].v4); if (clmd->sim_parms->vgroup_shrink > 0) shrink_factor = 1.0f - ((cloth->verts[spring->ij].shrink_factor + cloth->verts[spring->kl].shrink_factor) / 2.0f); else shrink_factor = 1.0f - clmd->sim_parms->shrink_min; spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest) * shrink_factor; spring->type = CLOTH_SPRING_TYPE_SHEAR; spring->stiffness = (cloth->verts[spring->kl].shear_stiff + cloth->verts[spring->ij].shear_stiff) / 2.0f; BLI_linklist_append ( &edgelist[spring->ij], spring ); BLI_linklist_append ( &edgelist[spring->kl], spring ); shear_springs++; BLI_linklist_prepend ( &cloth->springs, spring ); } edgeset = BLI_edgeset_new_ex(__func__, numedges); cloth->edgeset = edgeset; if (numfaces) { // bending springs search2 = cloth->springs; for ( i = struct_springs; i < struct_springs+shear_springs; i++ ) { if ( !search2 ) break; tspring2 = search2->link; search = edgelist[tspring2->kl]; while ( search ) { tspring = search->link; index2 = ( ( tspring->ij==tspring2->kl ) ? ( tspring->kl ) : ( tspring->ij ) ); // check for existing spring // check also if startpoint is equal to endpoint if ((index2 != tspring2->ij) && !BLI_edgeset_haskey(edgeset, tspring2->ij, index2)) { spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); if (!spring) { cloth_free_errorsprings(cloth, edgelist); return 0; } spring_verts_ordered_set(spring, tspring2->ij, index2); spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest); spring->type = CLOTH_SPRING_TYPE_BENDING; spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f; BLI_edgeset_insert(edgeset, spring->ij, spring->kl); bend_springs++; BLI_linklist_prepend ( &cloth->springs, spring ); } search = search->next; } search2 = search2->next; } } else if (struct_springs > 2) { /* bending springs for hair strands */ /* The current algorightm only goes through the edges in order of the mesh edges list */ /* and makes springs between the outer vert of edges sharing a vertice. This works just */ /* fine for hair, but not for user generated string meshes. This could/should be later */ /* extended to work with non-ordered edges so that it can be used for general "rope */ /* dynamics" without the need for the vertices or edges to be ordered through the length*/ /* of the strands. -jahka */ search = cloth->springs; search2 = search->next; while (search && search2) { tspring = search->link; tspring2 = search2->link; if (tspring->ij == tspring2->kl) { spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); if (!spring) { cloth_free_errorsprings(cloth, edgelist); return 0; } spring->ij = tspring2->ij; spring->kl = tspring->kl; spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest); spring->type = CLOTH_SPRING_TYPE_BENDING; spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f; bend_springs++; BLI_linklist_prepend ( &cloth->springs, spring ); } search = search->next; search2 = search2->next; } } /* note: the edges may already exist so run reinsert */ /* insert other near springs in edgeset AFTER bending springs are calculated (for selfcolls) */ for (i = 0; i < numedges; i++) { /* struct springs */ BLI_edgeset_add(edgeset, medge[i].v1, medge[i].v2); } for (i = 0; i < numfaces; i++) { /* edge springs */ if (mface[i].v4) { BLI_edgeset_add(edgeset, mface[i].v1, mface[i].v3); BLI_edgeset_add(edgeset, mface[i].v2, mface[i].v4); } } cloth->numsprings = struct_springs + shear_springs + bend_springs; cloth_free_edgelist(edgelist, numverts); #if 0 if (G.debug_value > 0) printf("avg_len: %f\n", clmd->sim_parms->avg_spring_len); #endif return 1; } /* cloth_build_springs */
static void createVertsTrisData(bContext *C, LinkNode* obs, int *nverts_r, float **verts_r, int *ntris_r, int **tris_r) { MVert *mvert; int nfaces= 0, *tri, i, curnverts, basenverts, curnfaces; MFace *mface; float co[3], wco[3]; Object *ob; LinkNode *oblink, *dmlink; DerivedMesh *dm; Scene* scene= CTX_data_scene(C); LinkNode* dms= NULL; int nverts, ntris, *tris; float *verts; nverts= 0; ntris= 0; /* calculate number of verts and tris */ for(oblink= obs; oblink; oblink= oblink->next) { ob= (Object*) oblink->link; dm= mesh_create_derived_no_virtual(scene, ob, NULL, CD_MASK_MESH); BLI_linklist_append(&dms, (void*)dm); nverts+= dm->getNumVerts(dm); nfaces= dm->getNumFaces(dm); ntris+= nfaces; /* resolve quad faces */ mface= dm->getFaceArray(dm); for(i= 0; i<nfaces; i++) { MFace* mf= &mface[i]; if(mf->v4) ntris+=1; } } /* create data */ verts= MEM_mallocN(sizeof(float)*3*nverts, "createVertsTrisData verts"); tris= MEM_mallocN(sizeof(int)*3*ntris, "createVertsTrisData faces"); basenverts= 0; tri= tris; for(oblink= obs, dmlink= dms; oblink && dmlink; oblink= oblink->next, dmlink= dmlink->next) { ob= (Object*) oblink->link; dm= (DerivedMesh*) dmlink->link; curnverts= dm->getNumVerts(dm); mvert= dm->getVertArray(dm); /* copy verts */ for(i= 0; i<curnverts; i++) { MVert *v= &mvert[i]; copy_v3_v3(co, v->co); mul_v3_m4v3(wco, ob->obmat, co); verts[3*(basenverts+i)+0]= wco[0]; verts[3*(basenverts+i)+1]= wco[2]; verts[3*(basenverts+i)+2]= wco[1]; } /* create tris */ curnfaces= dm->getNumFaces(dm); mface= dm->getFaceArray(dm); for(i= 0; i<curnfaces; i++) { MFace* mf= &mface[i]; tri[0]= basenverts + mf->v1; tri[1]= basenverts + mf->v3; tri[2]= basenverts + mf->v2; tri += 3; if(mf->v4) { tri[0]= basenverts + mf->v1; tri[1]= basenverts + mf->v4; tri[2]= basenverts + mf->v3; tri += 3; } } basenverts+= curnverts; } /* release derived mesh */ for(dmlink= dms; dmlink; dmlink= dmlink->next) { dm= (DerivedMesh*) dmlink->link; dm->release(dm); } BLI_linklist_free(dms, NULL); *nverts_r= nverts; *verts_r= verts; *ntris_r= ntris; *tris_r= tris; }