// ================================================================= // This functin is copied from source/blender/editors/mesh/mesh_data.c // // TODO: (As discussed with sergey-) : // Maybe move this function to blenderkernel/intern/mesh.c // and add definition to BKE_mesh.c // ================================================================= void MeshImporter::mesh_add_edges(Mesh *mesh, int len) { CustomData edata; MEdge *medge; int i, totedge; if (len == 0) return; totedge = mesh->totedge + len; /* update customdata */ CustomData_copy(&mesh->edata, &edata, CD_MASK_MESH, CD_DEFAULT, totedge); CustomData_copy_data(&mesh->edata, &edata, 0, 0, mesh->totedge); if (!CustomData_has_layer(&edata, CD_MEDGE)) CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, NULL, totedge); CustomData_free(&mesh->edata, mesh->totedge); mesh->edata = edata; BKE_mesh_update_customdata_pointers(mesh, false); /* new edges don't change tessellation */ /* set default flags */ medge = &mesh->medge[mesh->totedge]; for (i = 0; i < len; i++, medge++) medge->flag = ME_EDGEDRAW | ME_EDGERENDER | SELECT; mesh->totedge = totedge; }
static void mesh_add_faces(Mesh *mesh, int len) { CustomData fdata; MFace *mface; int i, totface; if(len == 0) return; totface= mesh->totface + len; /* new face count */ /* update customdata */ CustomData_copy(&mesh->fdata, &fdata, CD_MASK_MESH, CD_DEFAULT, totface); CustomData_copy_data(&mesh->fdata, &fdata, 0, 0, mesh->totface); if(!CustomData_has_layer(&fdata, CD_MFACE)) CustomData_add_layer(&fdata, CD_MFACE, CD_CALLOC, NULL, totface); CustomData_free(&mesh->fdata, mesh->totface); mesh->fdata= fdata; mesh_update_customdata_pointers(mesh); /* set default flags */ mface= &mesh->mface[mesh->totface]; for(i=0; i<len; i++, mface++) mface->flag= ME_FACE_SEL; mesh->totface= totface; }
void BKE_mesh_strip_loose_edges(Mesh *me) { MEdge *e; MLoop *l; int a, b; unsigned int *new_idx = MEM_mallocN(sizeof(int) * me->totedge, __func__); for (a = b = 0, e = me->medge; a < me->totedge; a++, e++) { if (e->v1 != e->v2) { if (a != b) { memcpy(&me->medge[b], e, sizeof(me->medge[b])); CustomData_copy_data(&me->edata, &me->edata, a, b, 1); } new_idx[a] = b; b++; } else { new_idx[a] = INVALID_LOOP_EDGE_MARKER; } } if (a != b) { CustomData_free_elem(&me->edata, b, a - b); me->totedge = b; } /* And now, update loops' edge indices. */ /* XXX We hope no loop was pointing to a striped edge! * Else, its e will be set to INVALID_LOOP_EDGE_MARKER :/ */ for (a = 0, l = me->mloop; a < me->totloop; a++, l++) { l->e = new_idx[l->e]; } MEM_freeN(new_idx); }
/* Set coordinate of vertex with given index. */ static void exporter_SetVert(ExportMeshData *export_data, int vert_index, float coord[3], int which_orig_mesh, int orig_vert_index) { DerivedMesh *dm = export_data->dm; DerivedMesh *dm_orig; MVert *mvert = export_data->mvert; BLI_assert(vert_index >= 0 && vert_index <= dm->getNumVerts(dm)); dm_orig = which_dm(export_data, which_orig_mesh); if (dm_orig) { BLI_assert(orig_vert_index >= 0 && orig_vert_index < dm_orig->getNumVerts(dm_orig)); mvert[vert_index] = which_mvert(export_data, which_orig_mesh)[orig_vert_index]; CustomData_copy_data(&dm_orig->vertData, &dm->vertData, orig_vert_index, vert_index, 1); } /* Set original index of the vertex. */ if (export_data->vert_origindex) { if (which_orig_mesh == CARVE_MESH_LEFT) { export_data->vert_origindex[vert_index] = orig_vert_index; } else { export_data->vert_origindex[vert_index] = ORIGINDEX_NONE; } } mul_v3_m4v3(mvert[vert_index].co, export_data->obimat, coord); }
static void mesh_add_verts(Mesh *mesh, int len) { CustomData vdata; MVert *mvert; int i, totvert; if(len == 0) return; totvert= mesh->totvert + len; CustomData_copy(&mesh->vdata, &vdata, CD_MASK_MESH, CD_DEFAULT, totvert); CustomData_copy_data(&mesh->vdata, &vdata, 0, 0, mesh->totvert); if(!CustomData_has_layer(&vdata, CD_MVERT)) CustomData_add_layer(&vdata, CD_MVERT, CD_CALLOC, NULL, totvert); CustomData_free(&mesh->vdata, mesh->totvert); mesh->vdata= vdata; mesh_update_customdata_pointers(mesh); /* scan the input list and insert the new vertices */ mvert= &mesh->mvert[mesh->totvert]; for(i=0; i<len; i++, mvert++) mvert->flag |= SELECT; /* set final vertex list size */ mesh->totvert= totvert; }
/* Set list vertex and edge which are adjucent to loop with given index. */ static void exporter_SetLoop(ExportMeshData *export_data, int loop_index, int vertex, int edge, int which_orig_mesh, int orig_loop_index) { DerivedMesh *dm = export_data->dm; MLoop *mloop = &export_data->mloop[loop_index]; DerivedMesh *dm_orig; BLI_assert(loop_index >= 0 && loop_index < dm->getNumLoops(dm)); BLI_assert(vertex >= 0 && vertex < dm->getNumVerts(dm)); BLI_assert(edge >= 0 && vertex < dm->getNumEdges(dm)); dm_orig = which_dm(export_data, which_orig_mesh); if (dm_orig) { BLI_assert(orig_loop_index >= 0 && orig_loop_index < dm_orig->getNumLoops(dm_orig)); /* Copy all loop layers, including mloop. */ *mloop = which_mloop(export_data, which_orig_mesh)[orig_loop_index]; CustomData_copy_data(&dm_orig->loopData, &dm->loopData, orig_loop_index, loop_index, 1); } /* Set original index of the loop. */ if (export_data->loop_origindex) { if (which_orig_mesh == CARVE_MESH_LEFT) { export_data->loop_origindex[loop_index] = orig_loop_index; } else { export_data->loop_origindex[loop_index] = ORIGINDEX_NONE; } } mloop->v = vertex; mloop->e = edge; }
static MFace *get_dface(Mesh *mesh, Mesh *split, int cur, int i, MFace *mf) { MFace *df = &split->mface[cur]; CustomData_copy_data(&mesh->fdata, &split->fdata, i, cur, 1); *df = *mf; return df; }
/* We need to keep this for edge creation (for now?), and some old readfile code... */ void BKE_mesh_strip_loose_faces(Mesh *me) { MFace *f; int a, b; for (a = b = 0, f = me->mface; a < me->totface; a++, f++) { if (f->v3) { if (a != b) { memcpy(&me->mface[b], f, sizeof(me->mface[b])); CustomData_copy_data(&me->fdata, &me->fdata, a, b, 1); } b++; } } if (a != b) { CustomData_free_elem(&me->fdata, b, a - b); me->totface = b; } }
/* Set vertices which are adjucent to the edge specified by it's index. */ static void exporter_SetEdge(ExportMeshData *export_data, int edge_index, int v1, int v2, int which_orig_mesh, int orig_edge_index) { DerivedMesh *dm = export_data->dm; MEdge *medge = &export_data->medge[edge_index]; DerivedMesh *dm_orig; BLI_assert(edge_index >= 0 && edge_index < dm->getNumEdges(dm)); BLI_assert(v1 >= 0 && v1 < dm->getNumVerts(dm)); BLI_assert(v2 >= 0 && v2 < dm->getNumVerts(dm)); dm_orig = which_dm(export_data, which_orig_mesh); if (dm_orig) { BLI_assert(orig_edge_index >= 0 && orig_edge_index < dm_orig->getNumEdges(dm_orig)); *medge = which_medge(export_data, which_orig_mesh)[orig_edge_index]; /* Copy all edge layers, including medge. */ CustomData_copy_data(&dm_orig->edgeData, &dm->edgeData, orig_edge_index, edge_index, 1); } /* Set original index of the edge. */ if (export_data->edge_origindex) { if (which_orig_mesh == CARVE_MESH_LEFT) { export_data->edge_origindex[edge_index] = orig_edge_index; } else { export_data->edge_origindex[edge_index] = ORIGINDEX_NONE; } } medge->v1 = v1; medge->v2 = v2; medge->flag |= ME_EDGEDRAW | ME_EDGERENDER; }
/* Note: It won't try to guess which loops of an invalid poly to remove! * this is the work of the caller, to mark those loops... * See e.g. BKE_mesh_validate_arrays(). */ void BKE_mesh_strip_loose_polysloops(Mesh *me) { MPoly *p; MLoop *l; int a, b; /* New loops idx! */ int *new_idx = MEM_mallocN(sizeof(int) * me->totloop, __func__); for (a = b = 0, p = me->mpoly; a < me->totpoly; a++, p++) { bool invalid = false; int i = p->loopstart; int stop = i + p->totloop; if (stop > me->totloop || stop < i) { invalid = true; } else { l = &me->mloop[i]; i = stop - i; /* If one of the poly's loops is invalid, the whole poly is invalid! */ for (; i--; l++) { if (l->e == INVALID_LOOP_EDGE_MARKER) { invalid = true; break; } } } if (p->totloop >= 3 && !invalid) { if (a != b) { memcpy(&me->mpoly[b], p, sizeof(me->mpoly[b])); CustomData_copy_data(&me->pdata, &me->pdata, a, b, 1); } b++; } } if (a != b) { CustomData_free_elem(&me->pdata, b, a - b); me->totpoly = b; } /* And now, get rid of invalid loops. */ for (a = b = 0, l = me->mloop; a < me->totloop; a++, l++) { if (l->e != INVALID_LOOP_EDGE_MARKER) { if (a != b) { memcpy(&me->mloop[b], l, sizeof(me->mloop[b])); CustomData_copy_data(&me->ldata, &me->ldata, a, b, 1); } new_idx[a] = b; b++; } else { /* XXX Theoretically, we should be able to not do this, as no remaining poly * should use any stripped loop. But for security's sake... */ new_idx[a] = -a; } } if (a != b) { CustomData_free_elem(&me->ldata, b, a - b); me->totloop = b; } /* And now, update polys' start loop index. */ /* Note: At this point, there should never be any poly using a striped loop! */ for (a = 0, p = me->mpoly; a < me->totpoly; a++, p++) { p->loopstart = new_idx[p->loopstart]; } MEM_freeN(new_idx); }
int join_mesh_exec(bContext *C, wmOperator *op) { Main *bmain= CTX_data_main(C); Scene *scene= CTX_data_scene(C); Object *ob= CTX_data_active_object(C); Material **matar, *ma; Mesh *me; MVert *mvert, *mv; MEdge *medge = NULL; MFace *mface = NULL; Key *key, *nkey=NULL; KeyBlock *kb, *okb, *kbn; float imat[4][4], cmat[4][4], *fp1, *fp2, curpos; int a, b, totcol, totmat=0, totedge=0, totvert=0, totface=0, ok=0; int vertofs, *matmap=NULL; int i, j, index, haskey=0, edgeofs, faceofs; bDeformGroup *dg, *odg; MDeformVert *dvert; CustomData vdata, edata, fdata; if(scene->obedit) { BKE_report(op->reports, RPT_WARNING, "Cant join while in editmode"); return OPERATOR_CANCELLED; } /* ob is the object we are adding geometry to */ if(!ob || ob->type!=OB_MESH) { BKE_report(op->reports, RPT_WARNING, "Active object is not a mesh"); return OPERATOR_CANCELLED; } /* count & check */ CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) { if(base->object->type==OB_MESH) { me= base->object->data; totvert+= me->totvert; totedge+= me->totedge; totface+= me->totface; totmat+= base->object->totcol; if(base->object == ob) ok= 1; /* check for shapekeys */ if(me->key) haskey++; } } CTX_DATA_END; /* that way the active object is always selected */ if(ok==0) { BKE_report(op->reports, RPT_WARNING, "Active object is not a selected mesh"); return OPERATOR_CANCELLED; } /* only join meshes if there are verts to join, there aren't too many, and we only had one mesh selected */ me= (Mesh *)ob->data; key= me->key; if(totvert==0 || totvert==me->totvert) { BKE_report(op->reports, RPT_WARNING, "No mesh data to join"); return OPERATOR_CANCELLED; } if(totvert > MESH_MAX_VERTS) { BKE_reportf(op->reports, RPT_WARNING, "Joining results in %d vertices, limit is " STRINGIFY(MESH_MAX_VERTS), totvert); return OPERATOR_CANCELLED; } /* new material indices and material array */ matar= MEM_callocN(sizeof(void*)*totmat, "join_mesh matar"); if (totmat) matmap= MEM_callocN(sizeof(int)*totmat, "join_mesh matmap"); totcol= ob->totcol; /* obact materials in new main array, is nicer start! */ for(a=0; a<ob->totcol; a++) { matar[a]= give_current_material(ob, a+1); id_us_plus((ID *)matar[a]); /* increase id->us : will be lowered later */ } /* - if destination mesh had shapekeys, move them somewhere safe, and set up placeholders * with arrays that are large enough to hold shapekey data for all meshes * - if destination mesh didn't have shapekeys, but we encountered some in the meshes we're * joining, set up a new keyblock and assign to the mesh */ if(key) { /* make a duplicate copy that will only be used here... (must remember to free it!) */ nkey= copy_key(key); /* for all keys in old block, clear data-arrays */ for(kb= key->block.first; kb; kb= kb->next) { if(kb->data) MEM_freeN(kb->data); kb->data= MEM_callocN(sizeof(float)*3*totvert, "join_shapekey"); kb->totelem= totvert; kb->weights= NULL; } } else if(haskey) { /* add a new key-block and add to the mesh */ key= me->key= add_key((ID *)me); key->type = KEY_RELATIVE; } /* first pass over objects - copying materials and vertexgroups across */ CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) { /* only act if a mesh, and not the one we're joining to */ if((ob!=base->object) && (base->object->type==OB_MESH)) { me= base->object->data; /* Join this object's vertex groups to the base one's */ for(dg=base->object->defbase.first; dg; dg=dg->next) { /* See if this group exists in the object (if it doesn't, add it to the end) */ if(!defgroup_find_name(ob, dg->name)) { odg = MEM_callocN(sizeof(bDeformGroup), "join deformGroup"); memcpy(odg, dg, sizeof(bDeformGroup)); BLI_addtail(&ob->defbase, odg); } } if(ob->defbase.first && ob->actdef==0) ob->actdef=1; if(me->totvert) { /* Add this object's materials to the base one's if they don't exist already (but only if limits not exceeded yet) */ if(totcol < MAXMAT) { for(a=1; a<=base->object->totcol; a++) { ma= give_current_material(base->object, a); for(b=0; b<totcol; b++) { if(ma == matar[b]) break; } if(b==totcol) { matar[b]= ma; if(ma) { id_us_plus(&ma->id); } totcol++; } if(totcol >= MAXMAT) break; } } /* if this mesh has shapekeys, check if destination mesh already has matching entries too */ if(me->key && key) { for(kb= me->key->block.first; kb; kb= kb->next) { /* if key doesn't exist in destination mesh, add it */ if(key_get_named_keyblock(key, kb->name) == NULL) { /* copy this existing one over to the new shapekey block */ kbn= MEM_dupallocN(kb); kbn->prev= kbn->next= NULL; /* adjust adrcode and other settings to fit (allocate a new data-array) */ kbn->data= MEM_callocN(sizeof(float)*3*totvert, "joined_shapekey"); kbn->totelem= totvert; kbn->weights= NULL; okb= key->block.last; curpos= (okb) ? okb->pos : -0.1f; if(key->type == KEY_RELATIVE) kbn->pos= curpos + 0.1f; else kbn->pos= curpos; BLI_addtail(&key->block, kbn); kbn->adrcode= key->totkey; key->totkey++; if(key->totkey==1) key->refkey= kbn; // XXX 2.5 Animato #if 0 /* also, copy corresponding ipo-curve to ipo-block if applicable */ if(me->key->ipo && key->ipo) { // FIXME... this is a luxury item! puts("FIXME: ignoring IPO's when joining shapekeys on Meshes for now..."); } #endif } } } } } } CTX_DATA_END; /* setup new data for destination mesh */ memset(&vdata, 0, sizeof(vdata)); memset(&edata, 0, sizeof(edata)); memset(&fdata, 0, sizeof(fdata)); mvert= CustomData_add_layer(&vdata, CD_MVERT, CD_CALLOC, NULL, totvert); medge= CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, NULL, totedge); mface= CustomData_add_layer(&fdata, CD_MFACE, CD_CALLOC, NULL, totface); vertofs= 0; edgeofs= 0; faceofs= 0; /* inverse transform for all selected meshes in this object */ invert_m4_m4(imat, ob->obmat); CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) { /* only join if this is a mesh */ if(base->object->type==OB_MESH) { me= base->object->data; if(me->totvert) { /* standard data */ CustomData_merge(&me->vdata, &vdata, CD_MASK_MESH, CD_DEFAULT, totvert); CustomData_copy_data(&me->vdata, &vdata, 0, vertofs, me->totvert); /* vertex groups */ dvert= CustomData_get(&vdata, vertofs, CD_MDEFORMVERT); /* NB: vertex groups here are new version */ if(dvert) { for(i=0; i<me->totvert; i++) { for(j=0; j<dvert[i].totweight; j++) { /* Find the old vertex group */ odg = BLI_findlink(&base->object->defbase, dvert[i].dw[j].def_nr); if(odg) { /* Search for a match in the new object, and set new index */ for(dg=ob->defbase.first, index=0; dg; dg=dg->next, index++) { if(!strcmp(dg->name, odg->name)) { dvert[i].dw[j].def_nr = index; break; } } } } } } /* if this is the object we're merging into, no need to do anything */ if(base->object != ob) { /* watch this: switch matmul order really goes wrong */ mul_m4_m4m4(cmat, base->object->obmat, imat); /* transform vertex coordinates into new space */ for(a=0, mv=mvert; a < me->totvert; a++, mv++) { mul_m4_v3(cmat, mv->co); } /* for each shapekey in destination mesh: * - if there's a matching one, copy it across (will need to transform vertices into new space...) * - otherwise, just copy own coordinates of mesh (no need to transform vertex coordinates into new space) */ if(key) { /* if this mesh has any shapekeys, check first, otherwise just copy coordinates */ for(kb= key->block.first; kb; kb= kb->next) { /* get pointer to where to write data for this mesh in shapekey's data array */ fp1= ((float *)kb->data) + (vertofs*3); /* check if this mesh has such a shapekey */ okb= key_get_named_keyblock(me->key, kb->name); if(okb) { /* copy this mesh's shapekey to the destination shapekey (need to transform first) */ fp2= ((float *)(okb->data)); for(a=0; a < me->totvert; a++, fp1+=3, fp2+=3) { VECCOPY(fp1, fp2); mul_m4_v3(cmat, fp1); } } else { /* copy this mesh's vertex coordinates to the destination shapekey */ mv= mvert; for(a=0; a < me->totvert; a++, fp1+=3, mv++) { VECCOPY(fp1, mv->co); } } } } } else { /* for each shapekey in destination mesh: * - if it was an 'original', copy the appropriate data from nkey * - otherwise, copy across plain coordinates (no need to transform coordinates) */ if(key) { for(kb= key->block.first; kb; kb= kb->next) { /* get pointer to where to write data for this mesh in shapekey's data array */ fp1= ((float *)kb->data) + (vertofs*3); /* check if this was one of the original shapekeys */ okb= key_get_named_keyblock(nkey, kb->name); if(okb) { /* copy this mesh's shapekey to the destination shapekey */ fp2= ((float *)(okb->data)); for(a=0; a < me->totvert; a++, fp1+=3, fp2+=3) { VECCOPY(fp1, fp2); } } else { /* copy base-coordinates to the destination shapekey */ mv= mvert; for(a=0; a < me->totvert; a++, fp1+=3, mv++) { VECCOPY(fp1, mv->co); } } } } } /* advance mvert pointer to end of base mesh's data */ mvert+= me->totvert; } if(me->totface) { /* make mapping for materials */ for(a=1; a<=base->object->totcol; a++) { ma= give_current_material(base->object, a); for(b=0; b<totcol; b++) { if(ma == matar[b]) { matmap[a-1]= b; break; } } } if(base->object!=ob) multiresModifier_prepare_join(scene, base->object, ob); CustomData_merge(&me->fdata, &fdata, CD_MASK_MESH, CD_DEFAULT, totface); CustomData_copy_data(&me->fdata, &fdata, 0, faceofs, me->totface); for(a=0; a<me->totface; a++, mface++) { mface->v1+= vertofs; mface->v2+= vertofs; mface->v3+= vertofs; if(mface->v4) mface->v4+= vertofs; if (matmap) mface->mat_nr= matmap[(int)mface->mat_nr]; else mface->mat_nr= 0; } faceofs += me->totface; } if(me->totedge) { CustomData_merge(&me->edata, &edata, CD_MASK_MESH, CD_DEFAULT, totedge); CustomData_copy_data(&me->edata, &edata, 0, edgeofs, me->totedge); for(a=0; a<me->totedge; a++, medge++) { medge->v1+= vertofs; medge->v2+= vertofs; } edgeofs += me->totedge; } /* vertofs is used to help newly added verts be reattached to their edge/face * (cannot be set earlier, or else reattaching goes wrong) */ vertofs += me->totvert; /* free base, now that data is merged */ if(base->object != ob) ED_base_object_free_and_unlink(bmain, scene, base); } } CTX_DATA_END; /* return to mesh we're merging to */ me= ob->data; CustomData_free(&me->vdata, me->totvert); CustomData_free(&me->edata, me->totedge); CustomData_free(&me->fdata, me->totface); me->totvert= totvert; me->totedge= totedge; me->totface= totface; me->vdata= vdata; me->edata= edata; me->fdata= fdata; mesh_update_customdata_pointers(me); /* old material array */ for(a=1; a<=ob->totcol; a++) { ma= ob->mat[a-1]; if(ma) ma->id.us--; } for(a=1; a<=me->totcol; a++) { ma= me->mat[a-1]; if(ma) ma->id.us--; } if(ob->mat) MEM_freeN(ob->mat); if(ob->matbits) MEM_freeN(ob->matbits); if(me->mat) MEM_freeN(me->mat); ob->mat= me->mat= NULL; ob->matbits= NULL; if(totcol) { me->mat= matar; ob->mat= MEM_callocN(sizeof(void *)*totcol, "join obmatar"); ob->matbits= MEM_callocN(sizeof(char)*totcol, "join obmatbits"); } else MEM_freeN(matar); ob->totcol= me->totcol= totcol; ob->colbits= 0; if (matmap) MEM_freeN(matmap); /* other mesh users */ test_object_materials((ID *)me); /* free temp copy of destination shapekeys (if applicable) */ if(nkey) { // XXX 2.5 Animato #if 0 /* free it's ipo too - both are not actually freed from memory yet as ID-blocks */ if(nkey->ipo) { free_ipo(nkey->ipo); BLI_remlink(&bmain->ipo, nkey->ipo); MEM_freeN(nkey->ipo); } #endif free_key(nkey); BLI_remlink(&bmain->key, nkey); MEM_freeN(nkey); } DAG_scene_sort(bmain, scene); // removed objects, need to rebuild dag before editmode call #if 0 ED_object_enter_editmode(C, EM_WAITCURSOR); ED_object_exit_editmode(C, EM_FREEDATA|EM_WAITCURSOR|EM_DO_UNDO); #else /* toggle editmode using lower level functions so this can be called from python */ make_editMesh(scene, ob); load_editMesh(scene, ob); free_editMesh(me->edit_mesh); MEM_freeN(me->edit_mesh); me->edit_mesh= NULL; DAG_id_tag_update(&ob->id, OB_RECALC_OB|OB_RECALC_DATA); #endif WM_event_add_notifier(C, NC_SCENE|ND_OB_ACTIVE, scene); return OPERATOR_FINISHED; }
/* Iterate over the CSG Output Descriptors and create a new DerivedMesh from them */ static DerivedMesh *ConvertCSGDescriptorsToDerivedMesh( CSG_FaceIteratorDescriptor *face_it, CSG_VertexIteratorDescriptor *vertex_it, float parinv[][4], float mapmat[][4], Material **mat, int *totmat, DerivedMesh *dm1, Object *ob1, DerivedMesh *dm2, Object *ob2) { DerivedMesh *result, *orig_dm; GHash *material_hash = NULL; Mesh *me1= (Mesh*)ob1->data; Mesh *me2= (Mesh*)ob2->data; int i; // create a new DerivedMesh result = CDDM_new(vertex_it->num_elements, 0, face_it->num_elements); CustomData_merge(&dm1->faceData, &result->faceData, CD_MASK_DERIVEDMESH, CD_DEFAULT, face_it->num_elements); CustomData_merge(&dm2->faceData, &result->faceData, CD_MASK_DERIVEDMESH, CD_DEFAULT, face_it->num_elements); // step through the vertex iterators: for (i = 0; !vertex_it->Done(vertex_it->it); i++) { CSG_IVertex csgvert; MVert *mvert = CDDM_get_vert(result, i); // retrieve a csg vertex from the boolean module vertex_it->Fill(vertex_it->it, &csgvert); vertex_it->Step(vertex_it->it); // we have to map the vertex coordinates back in the coordinate frame // of the resulting object, since it was computed in world space mul_v3_m4v3(mvert->co, parinv, csgvert.position); } // a hash table to remap materials to indices if (mat) { material_hash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "CSG_mat gh"); *totmat = 0; } // step through the face iterators for(i = 0; !face_it->Done(face_it->it); i++) { Mesh *orig_me; Object *orig_ob; Material *orig_mat; CSG_IFace csgface; MFace *mface; int orig_index, mat_nr; // retrieve a csg face from the boolean module face_it->Fill(face_it->it, &csgface); face_it->Step(face_it->it); // find the original mesh and data orig_ob = (csgface.orig_face < dm1->getNumFaces(dm1))? ob1: ob2; orig_dm = (csgface.orig_face < dm1->getNumFaces(dm1))? dm1: dm2; orig_me = (orig_ob == ob1)? me1: me2; orig_index = (orig_ob == ob1)? csgface.orig_face: csgface.orig_face - dm1->getNumFaces(dm1); // copy all face layers, including mface CustomData_copy_data(&orig_dm->faceData, &result->faceData, orig_index, i, 1); // set mface mface = CDDM_get_face(result, i); mface->v1 = csgface.vertex_index[0]; mface->v2 = csgface.vertex_index[1]; mface->v3 = csgface.vertex_index[2]; mface->v4 = (csgface.vertex_number == 4)? csgface.vertex_index[3]: 0; // set material, based on lookup in hash table orig_mat= give_current_material(orig_ob, mface->mat_nr+1); if (mat && orig_mat) { if (!BLI_ghash_haskey(material_hash, orig_mat)) { mat[*totmat] = orig_mat; mat_nr = mface->mat_nr = (*totmat)++; BLI_ghash_insert(material_hash, orig_mat, SET_INT_IN_POINTER(mat_nr)); } else mface->mat_nr = GET_INT_FROM_POINTER(BLI_ghash_lookup(material_hash, orig_mat)); } else mface->mat_nr = 0; InterpCSGFace(result, orig_dm, i, orig_index, csgface.vertex_number, (orig_me == me2)? mapmat: NULL); test_index_face(mface, &result->faceData, i, csgface.vertex_number); } if (material_hash) BLI_ghash_free(material_hash, NULL, NULL); CDDM_calc_edges(result); CDDM_calc_normals(result); return result; }
static DerivedMesh *applyModifier( ModifierData *md, Object *ob, DerivedMesh *dm, ModifierApplyFlag UNUSED(flag)) { DerivedMesh *result; const SolidifyModifierData *smd = (SolidifyModifierData *) md; MVert *mv, *mvert, *orig_mvert; MEdge *ed, *medge, *orig_medge; MLoop *ml, *mloop, *orig_mloop; MPoly *mp, *mpoly, *orig_mpoly; const unsigned int numVerts = (unsigned int)dm->getNumVerts(dm); const unsigned int numEdges = (unsigned int)dm->getNumEdges(dm); const unsigned int numFaces = (unsigned int)dm->getNumPolys(dm); const unsigned int numLoops = (unsigned int)dm->getNumLoops(dm); unsigned int newLoops = 0, newFaces = 0, newEdges = 0, newVerts = 0, rimVerts = 0; /* only use material offsets if we have 2 or more materials */ const short mat_nr_max = ob->totcol > 1 ? ob->totcol - 1 : 0; const short mat_ofs = mat_nr_max ? smd->mat_ofs : 0; const short mat_ofs_rim = mat_nr_max ? smd->mat_ofs_rim : 0; /* use for edges */ /* over-alloc new_vert_arr, old_vert_arr */ unsigned int *new_vert_arr = NULL; STACK_DECLARE(new_vert_arr); unsigned int *new_edge_arr = NULL; STACK_DECLARE(new_edge_arr); unsigned int *old_vert_arr = MEM_callocN(sizeof(*old_vert_arr) * (size_t)numVerts, "old_vert_arr in solidify"); unsigned int *edge_users = NULL; char *edge_order = NULL; float (*vert_nors)[3] = NULL; float (*face_nors)[3] = NULL; const bool need_face_normals = (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) || (smd->flag & MOD_SOLIDIFY_EVEN); const float ofs_orig = -(((-smd->offset_fac + 1.0f) * 0.5f) * smd->offset); const float ofs_new = smd->offset + ofs_orig; const float offset_fac_vg = smd->offset_fac_vg; const float offset_fac_vg_inv = 1.0f - smd->offset_fac_vg; const bool do_flip = (smd->flag & MOD_SOLIDIFY_FLIP) != 0; const bool do_clamp = (smd->offset_clamp != 0.0f); const bool do_shell = ((smd->flag & MOD_SOLIDIFY_RIM) && (smd->flag & MOD_SOLIDIFY_NOSHELL)) == 0; /* weights */ MDeformVert *dvert; const bool defgrp_invert = (smd->flag & MOD_SOLIDIFY_VGROUP_INV) != 0; int defgrp_index; /* array size is doubled in case of using a shell */ const unsigned int stride = do_shell ? 2 : 1; modifier_get_vgroup(ob, dm, smd->defgrp_name, &dvert, &defgrp_index); orig_mvert = dm->getVertArray(dm); orig_medge = dm->getEdgeArray(dm); orig_mloop = dm->getLoopArray(dm); orig_mpoly = dm->getPolyArray(dm); if (need_face_normals) { /* calculate only face normals */ face_nors = MEM_mallocN(sizeof(*face_nors) * (size_t)numFaces, __func__); BKE_mesh_calc_normals_poly( orig_mvert, NULL, (int)numVerts, orig_mloop, orig_mpoly, (int)numLoops, (int)numFaces, face_nors, true); } STACK_INIT(new_vert_arr, numVerts * 2); STACK_INIT(new_edge_arr, numEdges * 2); if (smd->flag & MOD_SOLIDIFY_RIM) { BLI_bitmap *orig_mvert_tag = BLI_BITMAP_NEW(numVerts, __func__); unsigned int eidx; unsigned int i; #define INVALID_UNUSED ((unsigned int)-1) #define INVALID_PAIR ((unsigned int)-2) new_vert_arr = MEM_mallocN(sizeof(*new_vert_arr) * (size_t)(numVerts * 2), __func__); new_edge_arr = MEM_mallocN(sizeof(*new_edge_arr) * (size_t)((numEdges * 2) + numVerts), __func__); edge_users = MEM_mallocN(sizeof(*edge_users) * (size_t)numEdges, "solid_mod edges"); edge_order = MEM_mallocN(sizeof(*edge_order) * (size_t)numEdges, "solid_mod eorder"); /* save doing 2 loops here... */ #if 0 copy_vn_i(edge_users, numEdges, INVALID_UNUSED); #endif for (eidx = 0, ed = orig_medge; eidx < numEdges; eidx++, ed++) { edge_users[eidx] = INVALID_UNUSED; } for (i = 0, mp = orig_mpoly; i < numFaces; i++, mp++) { MLoop *ml_prev; int j; ml = orig_mloop + mp->loopstart; ml_prev = ml + (mp->totloop - 1); for (j = 0; j < mp->totloop; j++, ml++) { /* add edge user */ eidx = ml_prev->e; if (edge_users[eidx] == INVALID_UNUSED) { ed = orig_medge + eidx; BLI_assert(ELEM(ml_prev->v, ed->v1, ed->v2) && ELEM(ml->v, ed->v1, ed->v2)); edge_users[eidx] = (ml_prev->v > ml->v) == (ed->v1 < ed->v2) ? i : (i + numFaces); edge_order[eidx] = j; } else { edge_users[eidx] = INVALID_PAIR; } ml_prev = ml; } } for (eidx = 0, ed = orig_medge; eidx < numEdges; eidx++, ed++) { if (!ELEM(edge_users[eidx], INVALID_UNUSED, INVALID_PAIR)) { BLI_BITMAP_ENABLE(orig_mvert_tag, ed->v1); BLI_BITMAP_ENABLE(orig_mvert_tag, ed->v2); STACK_PUSH(new_edge_arr, eidx); newFaces++; newLoops += 4; } } for (i = 0; i < numVerts; i++) { if (BLI_BITMAP_TEST(orig_mvert_tag, i)) { old_vert_arr[i] = STACK_SIZE(new_vert_arr); STACK_PUSH(new_vert_arr, i); rimVerts++; } else { old_vert_arr[i] = INVALID_UNUSED; } } MEM_freeN(orig_mvert_tag); } if (do_shell == false) { /* only add rim vertices */ newVerts = rimVerts; /* each extruded face needs an opposite edge */ newEdges = newFaces; } else { /* (stride == 2) in this case, so no need to add newVerts/newEdges */ BLI_assert(newVerts == 0); BLI_assert(newEdges == 0); } if (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) { vert_nors = MEM_callocN(sizeof(float) * (size_t)numVerts * 3, "mod_solid_vno_hq"); dm_calc_normal(dm, face_nors, vert_nors); } result = CDDM_from_template(dm, (int)((numVerts * stride) + newVerts), (int)((numEdges * stride) + newEdges + rimVerts), 0, (int)((numLoops * stride) + newLoops), (int)((numFaces * stride) + newFaces)); mpoly = CDDM_get_polys(result); mloop = CDDM_get_loops(result); medge = CDDM_get_edges(result); mvert = CDDM_get_verts(result); if (do_shell) { DM_copy_vert_data(dm, result, 0, 0, (int)numVerts); DM_copy_vert_data(dm, result, 0, (int)numVerts, (int)numVerts); DM_copy_edge_data(dm, result, 0, 0, (int)numEdges); DM_copy_edge_data(dm, result, 0, (int)numEdges, (int)numEdges); DM_copy_loop_data(dm, result, 0, 0, (int)numLoops); DM_copy_loop_data(dm, result, 0, (int)numLoops, (int)numLoops); DM_copy_poly_data(dm, result, 0, 0, (int)numFaces); DM_copy_poly_data(dm, result, 0, (int)numFaces, (int)numFaces); } else { int i, j; DM_copy_vert_data(dm, result, 0, 0, (int)numVerts); for (i = 0, j = (int)numVerts; i < numVerts; i++) { if (old_vert_arr[i] != INVALID_UNUSED) { DM_copy_vert_data(dm, result, i, j, 1); j++; } } DM_copy_edge_data(dm, result, 0, 0, (int)numEdges); for (i = 0, j = (int)numEdges; i < numEdges; i++) { if (!ELEM(edge_users[i], INVALID_UNUSED, INVALID_PAIR)) { MEdge *ed_src, *ed_dst; DM_copy_edge_data(dm, result, i, j, 1); ed_src = &medge[i]; ed_dst = &medge[j]; ed_dst->v1 = old_vert_arr[ed_src->v1] + numVerts; ed_dst->v2 = old_vert_arr[ed_src->v2] + numVerts; j++; } } /* will be created later */ DM_copy_loop_data(dm, result, 0, 0, (int)numLoops); DM_copy_poly_data(dm, result, 0, 0, (int)numFaces); } #undef INVALID_UNUSED #undef INVALID_PAIR /* initializes: (i_end, do_shell_align, mv) */ #define INIT_VERT_ARRAY_OFFSETS(test) \ if (((ofs_new >= ofs_orig) == do_flip) == test) { \ i_end = numVerts; \ do_shell_align = true; \ mv = mvert; \ } \ else { \ if (do_shell) { \ i_end = numVerts; \ do_shell_align = true; \ } \ else { \ i_end = newVerts ; \ do_shell_align = false; \ } \ mv = &mvert[numVerts]; \ } (void)0 /* flip normals */ if (do_shell) { unsigned int i; mp = mpoly + numFaces; for (i = 0; i < dm->numPolyData; i++, mp++) { MLoop *ml2; unsigned int e; int j; /* reverses the loop direction (MLoop.v as well as custom-data) * MLoop.e also needs to be corrected too, done in a separate loop below. */ ml2 = mloop + mp->loopstart + dm->numLoopData; for (j = 0; j < mp->totloop; j++) { CustomData_copy_data(&dm->loopData, &result->loopData, mp->loopstart + j, mp->loopstart + (mp->totloop - j - 1) + dm->numLoopData, 1); } if (mat_ofs) { mp->mat_nr += mat_ofs; CLAMP(mp->mat_nr, 0, mat_nr_max); } e = ml2[0].e; for (j = 0; j < mp->totloop - 1; j++) { ml2[j].e = ml2[j + 1].e; } ml2[mp->totloop - 1].e = e; mp->loopstart += dm->numLoopData; for (j = 0; j < mp->totloop; j++) { ml2[j].e += numEdges; ml2[j].v += numVerts; } } for (i = 0, ed = medge + numEdges; i < numEdges; i++, ed++) { ed->v1 += numVerts; ed->v2 += numVerts; } } /* note, copied vertex layers don't have flipped normals yet. do this after applying offset */ if ((smd->flag & MOD_SOLIDIFY_EVEN) == 0) { /* no even thickness, very simple */ float scalar_short; float scalar_short_vgroup; /* for clamping */ float *vert_lens = NULL; const float offset = fabsf(smd->offset) * smd->offset_clamp; const float offset_sq = offset * offset; if (do_clamp) { unsigned int i; vert_lens = MEM_mallocN(sizeof(float) * numVerts, "vert_lens"); copy_vn_fl(vert_lens, (int)numVerts, FLT_MAX); for (i = 0; i < numEdges; i++) { const float ed_len_sq = len_squared_v3v3(mvert[medge[i].v1].co, mvert[medge[i].v2].co); vert_lens[medge[i].v1] = min_ff(vert_lens[medge[i].v1], ed_len_sq); vert_lens[medge[i].v2] = min_ff(vert_lens[medge[i].v2], ed_len_sq); } } if (ofs_new != 0.0f) { unsigned int i_orig, i_end; bool do_shell_align; scalar_short = scalar_short_vgroup = ofs_new / 32767.0f; INIT_VERT_ARRAY_OFFSETS(false); for (i_orig = 0; i_orig < i_end; i_orig++, mv++) { const unsigned int i = do_shell_align ? i_orig : new_vert_arr[i_orig]; if (dvert) { MDeformVert *dv = &dvert[i]; if (defgrp_invert) scalar_short_vgroup = 1.0f - defvert_find_weight(dv, defgrp_index); else scalar_short_vgroup = defvert_find_weight(dv, defgrp_index); scalar_short_vgroup = (offset_fac_vg + (scalar_short_vgroup * offset_fac_vg_inv)) * scalar_short; } if (do_clamp) { /* always reset becaise we may have set before */ if (dvert == NULL) { scalar_short_vgroup = scalar_short; } if (vert_lens[i] < offset_sq) { float scalar = sqrtf(vert_lens[i]) / offset; scalar_short_vgroup *= scalar; } } madd_v3v3short_fl(mv->co, mv->no, scalar_short_vgroup); } } if (ofs_orig != 0.0f) { unsigned int i_orig, i_end; bool do_shell_align; scalar_short = scalar_short_vgroup = ofs_orig / 32767.0f; /* as above but swapped */ INIT_VERT_ARRAY_OFFSETS(true); for (i_orig = 0; i_orig < i_end; i_orig++, mv++) { const unsigned int i = do_shell_align ? i_orig : new_vert_arr[i_orig]; if (dvert) { MDeformVert *dv = &dvert[i]; if (defgrp_invert) scalar_short_vgroup = 1.0f - defvert_find_weight(dv, defgrp_index); else scalar_short_vgroup = defvert_find_weight(dv, defgrp_index); scalar_short_vgroup = (offset_fac_vg + (scalar_short_vgroup * offset_fac_vg_inv)) * scalar_short; } if (do_clamp) { /* always reset becaise we may have set before */ if (dvert == NULL) { scalar_short_vgroup = scalar_short; } if (vert_lens[i] < offset_sq) { float scalar = sqrtf(vert_lens[i]) / offset; scalar_short_vgroup *= scalar; } } madd_v3v3short_fl(mv->co, mv->no, scalar_short_vgroup); } } if (do_clamp) { MEM_freeN(vert_lens); } } else { #ifdef USE_NONMANIFOLD_WORKAROUND const bool check_non_manifold = (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) != 0; #endif /* same as EM_solidify() in editmesh_lib.c */ float *vert_angles = MEM_callocN(sizeof(float) * numVerts * 2, "mod_solid_pair"); /* 2 in 1 */ float *vert_accum = vert_angles + numVerts; unsigned int vidx; unsigned int i; if (vert_nors == NULL) { vert_nors = MEM_mallocN(sizeof(float) * numVerts * 3, "mod_solid_vno"); for (i = 0, mv = mvert; i < numVerts; i++, mv++) { normal_short_to_float_v3(vert_nors[i], mv->no); } } for (i = 0, mp = mpoly; i < numFaces; i++, mp++) { /* #BKE_mesh_calc_poly_angles logic is inlined here */ float nor_prev[3]; float nor_next[3]; int i_curr = mp->totloop - 1; int i_next = 0; ml = &mloop[mp->loopstart]; sub_v3_v3v3(nor_prev, mvert[ml[i_curr - 1].v].co, mvert[ml[i_curr].v].co); normalize_v3(nor_prev); while (i_next < mp->totloop) { float angle; sub_v3_v3v3(nor_next, mvert[ml[i_curr].v].co, mvert[ml[i_next].v].co); normalize_v3(nor_next); angle = angle_normalized_v3v3(nor_prev, nor_next); /* --- not related to angle calc --- */ if (angle < FLT_EPSILON) { angle = FLT_EPSILON; } vidx = ml[i_curr].v; vert_accum[vidx] += angle; #ifdef USE_NONMANIFOLD_WORKAROUND /* skip 3+ face user edges */ if ((check_non_manifold == false) || LIKELY(((orig_medge[ml[i_curr].e].flag & ME_EDGE_TMP_TAG) == 0) && ((orig_medge[ml[i_next].e].flag & ME_EDGE_TMP_TAG) == 0))) { vert_angles[vidx] += shell_v3v3_normalized_to_dist(vert_nors[vidx], face_nors[i]) * angle; } else { vert_angles[vidx] += angle; } #else vert_angles[vidx] += shell_v3v3_normalized_to_dist(vert_nors[vidx], face_nors[i]) * angle; #endif /* --- end non-angle-calc section --- */ /* step */ copy_v3_v3(nor_prev, nor_next); i_curr = i_next; i_next++; } } /* vertex group support */ if (dvert) { MDeformVert *dv = dvert; float scalar; if (defgrp_invert) { for (i = 0; i < numVerts; i++, dv++) { scalar = 1.0f - defvert_find_weight(dv, defgrp_index); scalar = offset_fac_vg + (scalar * offset_fac_vg_inv); vert_angles[i] *= scalar; } } else { for (i = 0; i < numVerts; i++, dv++) { scalar = defvert_find_weight(dv, defgrp_index); scalar = offset_fac_vg + (scalar * offset_fac_vg_inv); vert_angles[i] *= scalar; } } } if (do_clamp) { float *vert_lens_sq = MEM_mallocN(sizeof(float) * numVerts, "vert_lens"); const float offset = fabsf(smd->offset) * smd->offset_clamp; const float offset_sq = offset * offset; copy_vn_fl(vert_lens_sq, (int)numVerts, FLT_MAX); for (i = 0; i < numEdges; i++) { const float ed_len = len_squared_v3v3(mvert[medge[i].v1].co, mvert[medge[i].v2].co); vert_lens_sq[medge[i].v1] = min_ff(vert_lens_sq[medge[i].v1], ed_len); vert_lens_sq[medge[i].v2] = min_ff(vert_lens_sq[medge[i].v2], ed_len); } for (i = 0; i < numVerts; i++) { if (vert_lens_sq[i] < offset_sq) { float scalar = sqrtf(vert_lens_sq[i]) / offset; vert_angles[i] *= scalar; } } MEM_freeN(vert_lens_sq); } if (ofs_new != 0.0f) { unsigned int i_orig, i_end; bool do_shell_align; INIT_VERT_ARRAY_OFFSETS(false); for (i_orig = 0; i_orig < i_end; i_orig++, mv++) { const unsigned int i_other = do_shell_align ? i_orig : new_vert_arr[i_orig]; if (vert_accum[i_other]) { /* zero if unselected */ madd_v3_v3fl(mv->co, vert_nors[i_other], ofs_new * (vert_angles[i_other] / vert_accum[i_other])); } } } if (ofs_orig != 0.0f) { unsigned int i_orig, i_end; bool do_shell_align; /* same as above but swapped, intentional use of 'ofs_new' */ INIT_VERT_ARRAY_OFFSETS(true); for (i_orig = 0; i_orig < i_end; i_orig++, mv++) { const unsigned int i_other = do_shell_align ? i_orig : new_vert_arr[i_orig]; if (vert_accum[i_other]) { /* zero if unselected */ madd_v3_v3fl(mv->co, vert_nors[i_other], ofs_orig * (vert_angles[i_other] / vert_accum[i_other])); } } } MEM_freeN(vert_angles); } if (vert_nors) MEM_freeN(vert_nors); /* must recalculate normals with vgroups since they can displace unevenly [#26888] */ if ((dm->dirty & DM_DIRTY_NORMALS) || (smd->flag & MOD_SOLIDIFY_RIM) || dvert) { result->dirty |= DM_DIRTY_NORMALS; } else if (do_shell) { unsigned int i; /* flip vertex normals for copied verts */ mv = mvert + numVerts; for (i = 0; i < numVerts; i++, mv++) { negate_v3_short(mv->no); } } if (smd->flag & MOD_SOLIDIFY_RIM) { unsigned int i; /* bugger, need to re-calculate the normals for the new edge faces. * This could be done in many ways, but probably the quickest way * is to calculate the average normals for side faces only. * Then blend them with the normals of the edge verts. * * at the moment its easiest to allocate an entire array for every vertex, * even though we only need edge verts - campbell */ #define SOLIDIFY_SIDE_NORMALS #ifdef SOLIDIFY_SIDE_NORMALS const bool do_side_normals = !(result->dirty & DM_DIRTY_NORMALS); /* annoying to allocate these since we only need the edge verts, */ float (*edge_vert_nos)[3] = do_side_normals ? MEM_callocN(sizeof(float) * numVerts * 3, __func__) : NULL; float nor[3]; #endif const unsigned char crease_rim = smd->crease_rim * 255.0f; const unsigned char crease_outer = smd->crease_outer * 255.0f; const unsigned char crease_inner = smd->crease_inner * 255.0f; int *origindex_edge; int *orig_ed; unsigned int j; if (crease_rim || crease_outer || crease_inner) { result->cd_flag |= ME_CDFLAG_EDGE_CREASE; } /* add faces & edges */ origindex_edge = result->getEdgeDataArray(result, CD_ORIGINDEX); ed = &medge[(numEdges * stride) + newEdges]; /* start after copied edges */ orig_ed = &origindex_edge[(numEdges * stride) + newEdges]; for (i = 0; i < rimVerts; i++, ed++, orig_ed++) { ed->v1 = new_vert_arr[i]; ed->v2 = (do_shell ? new_vert_arr[i] : i) + numVerts; ed->flag |= ME_EDGEDRAW; *orig_ed = ORIGINDEX_NONE; if (crease_rim) { ed->crease = crease_rim; } } /* faces */ mp = mpoly + (numFaces * stride); ml = mloop + (numLoops * stride); j = 0; for (i = 0; i < newFaces; i++, mp++) { unsigned int eidx = new_edge_arr[i]; unsigned int fidx = edge_users[eidx]; int k1, k2; bool flip; if (fidx >= numFaces) { fidx -= numFaces; flip = true; } else { flip = false; } ed = medge + eidx; /* copy most of the face settings */ DM_copy_poly_data(dm, result, (int)fidx, (int)((numFaces * stride) + i), 1); mp->loopstart = (int)(j + (numLoops * stride)); mp->flag = mpoly[fidx].flag; /* notice we use 'mp->totloop' which is later overwritten, * we could lookup the original face but theres no point since this is a copy * and will have the same value, just take care when changing order of assignment */ k1 = mpoly[fidx].loopstart + (((edge_order[eidx] - 1) + mp->totloop) % mp->totloop); /* prev loop */ k2 = mpoly[fidx].loopstart + (edge_order[eidx]); mp->totloop = 4; CustomData_copy_data(&dm->loopData, &result->loopData, k2, (int)((numLoops * stride) + j + 0), 1); CustomData_copy_data(&dm->loopData, &result->loopData, k1, (int)((numLoops * stride) + j + 1), 1); CustomData_copy_data(&dm->loopData, &result->loopData, k1, (int)((numLoops * stride) + j + 2), 1); CustomData_copy_data(&dm->loopData, &result->loopData, k2, (int)((numLoops * stride) + j + 3), 1); if (flip == false) { ml[j].v = ed->v1; ml[j++].e = eidx; ml[j].v = ed->v2; ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v2] + newEdges; ml[j].v = (do_shell ? ed->v2 : old_vert_arr[ed->v2]) + numVerts; ml[j++].e = (do_shell ? eidx : i) + numEdges; ml[j].v = (do_shell ? ed->v1 : old_vert_arr[ed->v1]) + numVerts; ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v1] + newEdges; } else { ml[j].v = ed->v2; ml[j++].e = eidx; ml[j].v = ed->v1; ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v1] + newEdges; ml[j].v = (do_shell ? ed->v1 : old_vert_arr[ed->v1]) + numVerts; ml[j++].e = (do_shell ? eidx : i) + numEdges; ml[j].v = (do_shell ? ed->v2 : old_vert_arr[ed->v2]) + numVerts; ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v2] + newEdges; } origindex_edge[ml[j - 3].e] = ORIGINDEX_NONE; origindex_edge[ml[j - 1].e] = ORIGINDEX_NONE; /* use the next material index if option enabled */ if (mat_ofs_rim) { mp->mat_nr += mat_ofs_rim; CLAMP(mp->mat_nr, 0, mat_nr_max); } if (crease_outer) { /* crease += crease_outer; without wrapping */ char *cr = &(ed->crease); int tcr = *cr + crease_outer; *cr = tcr > 255 ? 255 : tcr; } if (crease_inner) { /* crease += crease_inner; without wrapping */ char *cr = &(medge[numEdges + (do_shell ? eidx : i)].crease); int tcr = *cr + crease_inner; *cr = tcr > 255 ? 255 : tcr; } #ifdef SOLIDIFY_SIDE_NORMALS if (do_side_normals) { normal_quad_v3(nor, mvert[ml[j - 4].v].co, mvert[ml[j - 3].v].co, mvert[ml[j - 2].v].co, mvert[ml[j - 1].v].co); add_v3_v3(edge_vert_nos[ed->v1], nor); add_v3_v3(edge_vert_nos[ed->v2], nor); } #endif } #ifdef SOLIDIFY_SIDE_NORMALS if (do_side_normals) { ed = medge + (numEdges * stride); for (i = 0; i < rimVerts; i++, ed++) { float nor_cpy[3]; short *nor_short; int k; /* note, only the first vertex (lower half of the index) is calculated */ normalize_v3_v3(nor_cpy, edge_vert_nos[ed->v1]); for (k = 0; k < 2; k++) { /* loop over both verts of the edge */ nor_short = mvert[*(&ed->v1 + k)].no; normal_short_to_float_v3(nor, nor_short); add_v3_v3(nor, nor_cpy); normalize_v3(nor); normal_float_to_short_v3(nor_short, nor); } } MEM_freeN(edge_vert_nos); } #endif MEM_freeN(new_vert_arr); MEM_freeN(new_edge_arr); MEM_freeN(edge_users); MEM_freeN(edge_order); } if (old_vert_arr) MEM_freeN(old_vert_arr); if (face_nors) MEM_freeN(face_nors); if (numFaces == 0 && numEdges != 0) { modifier_setError(md, "Faces needed for useful output"); } return result; }
/* Set list of adjucent loops to the poly specified by it's index. */ static void exporter_SetPoly(ExportMeshData *export_data, int poly_index, int start_loop, int num_loops, int which_orig_mesh, int orig_poly_index) { DerivedMesh *dm = export_data->dm; MPoly *mpoly = &export_data->mpoly[poly_index]; DerivedMesh *dm_orig; int i; /* Poly is always to be either from left or right operand. */ dm_orig = which_dm(export_data, which_orig_mesh); BLI_assert(poly_index >= 0 && poly_index < dm->getNumPolys(dm)); BLI_assert(start_loop >= 0 && start_loop <= dm->getNumLoops(dm) - num_loops); BLI_assert(num_loops >= 3); BLI_assert(dm_orig != NULL); BLI_assert(orig_poly_index >= 0 && orig_poly_index < dm_orig->getNumPolys(dm_orig)); /* Copy all poly layers, including mpoly. */ *mpoly = which_mpoly(export_data, which_orig_mesh)[orig_poly_index]; CustomData_copy_data(&dm_orig->polyData, &dm->polyData, orig_poly_index, poly_index, 1); /* Set material of the curren poly. * This would re-map materials from right operand to materials from the * left one as well. */ setMPolyMaterial(export_data, mpoly, which_orig_mesh); /* Set original index of the poly. */ if (export_data->poly_origindex) { if (which_orig_mesh == CARVE_MESH_LEFT) { export_data->poly_origindex[poly_index] = orig_poly_index; } else { export_data->poly_origindex[poly_index] = ORIGINDEX_NONE; } } /* Set poly data itself. */ mpoly->loopstart = start_loop; mpoly->totloop = num_loops; /* Interpolate data for poly loops. */ { MVert *source_mverts = which_mvert(export_data, which_orig_mesh); MLoop *source_mloops = which_mloop(export_data, which_orig_mesh); MPoly *source_mpolys = which_mpoly(export_data, which_orig_mesh); MPoly *source_poly = &source_mpolys[orig_poly_index]; MVert *target_mverts = export_data->mvert; MLoop *target_mloops = export_data->mloop; float (*transform)[4] = NULL; if (which_orig_mesh == CARVE_MESH_RIGHT) { transform = export_data->left_to_right_mat; } for (i = 0; i < mpoly->totloop; i++) { DM_loop_interp_from_poly(dm_orig, source_mverts, source_mloops, source_poly, dm, target_mverts, target_mloops, transform, i + mpoly->loopstart); } } }
static Mesh *explodeMesh(ExplodeModifierData *emd, ParticleSystemModifierData *psmd, const ModifierEvalContext *ctx, Scene *scene, Mesh *to_explode) { Mesh *explode, *mesh = to_explode; MFace *mf = NULL, *mface; /* ParticleSettings *part=psmd->psys->part; */ /* UNUSED */ ParticleSimulationData sim = {NULL}; ParticleData *pa = NULL, *pars = psmd->psys->particles; ParticleKey state, birth; EdgeHash *vertpahash; EdgeHashIterator *ehi; float *vertco = NULL, imat[4][4]; float rot[4]; float cfra; /* float timestep; */ const int *facepa = emd->facepa; int totdup = 0, totvert = 0, totface = 0, totpart = 0, delface = 0; int i, v, u; unsigned int ed_v1, ed_v2, mindex = 0; MTFace *mtface = NULL, *mtf; totface = mesh->totface; totvert = mesh->totvert; mface = mesh->mface; totpart = psmd->psys->totpart; sim.depsgraph = ctx->depsgraph; sim.scene = scene; sim.ob = ctx->object; sim.psys = psmd->psys; sim.psmd = psmd; /* timestep = psys_get_timestep(&sim); */ cfra = BKE_scene_frame_get(scene); /* hash table for vertice <-> particle relations */ vertpahash = BLI_edgehash_new(__func__); for (i = 0; i < totface; i++) { if (facepa[i] != totpart) { pa = pars + facepa[i]; if ((pa->alive == PARS_UNBORN && (emd->flag & eExplodeFlag_Unborn) == 0) || (pa->alive == PARS_ALIVE && (emd->flag & eExplodeFlag_Alive) == 0) || (pa->alive == PARS_DEAD && (emd->flag & eExplodeFlag_Dead) == 0)) { delface++; continue; } } /* do mindex + totvert to ensure the vertex index to be the first * with BLI_edgehashIterator_getKey */ if (facepa[i] == totpart || cfra < (pars + facepa[i])->time) { mindex = totvert + totpart; } else { mindex = totvert + facepa[i]; } mf = &mface[i]; /* set face vertices to exist in particle group */ BLI_edgehash_reinsert(vertpahash, mf->v1, mindex, NULL); BLI_edgehash_reinsert(vertpahash, mf->v2, mindex, NULL); BLI_edgehash_reinsert(vertpahash, mf->v3, mindex, NULL); if (mf->v4) { BLI_edgehash_reinsert(vertpahash, mf->v4, mindex, NULL); } } /* make new vertice indexes & count total vertices after duplication */ ehi = BLI_edgehashIterator_new(vertpahash); for (; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) { BLI_edgehashIterator_setValue(ehi, POINTER_FROM_INT(totdup)); totdup++; } BLI_edgehashIterator_free(ehi); /* the final duplicated vertices */ explode = BKE_mesh_new_nomain_from_template(mesh, totdup, 0, totface - delface, 0, 0); mtface = CustomData_get_layer_named(&explode->fdata, CD_MTFACE, emd->uvname); /*dupvert = CDDM_get_verts(explode);*/ /* getting back to object space */ invert_m4_m4(imat, ctx->object->obmat); psmd->psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); /* duplicate & displace vertices */ ehi = BLI_edgehashIterator_new(vertpahash); for (; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) { MVert source; MVert *dest; /* get particle + vertex from hash */ BLI_edgehashIterator_getKey(ehi, &ed_v1, &ed_v2); ed_v2 -= totvert; v = POINTER_AS_INT(BLI_edgehashIterator_getValue(ehi)); source = mesh->mvert[ed_v1]; dest = &explode->mvert[v]; CustomData_copy_data(&mesh->vdata, &explode->vdata, ed_v1, v, 1); *dest = source; if (ed_v2 != totpart) { /* get particle */ pa = pars + ed_v2; psys_get_birth_coords(&sim, pa, &birth, 0, 0); state.time = cfra; psys_get_particle_state(&sim, ed_v2, &state, 1); vertco = explode->mvert[v].co; mul_m4_v3(ctx->object->obmat, vertco); sub_v3_v3(vertco, birth.co); /* apply rotation, size & location */ sub_qt_qtqt(rot, state.rot, birth.rot); mul_qt_v3(rot, vertco); if (emd->flag & eExplodeFlag_PaSize) { mul_v3_fl(vertco, pa->size); } add_v3_v3(vertco, state.co); mul_m4_v3(imat, vertco); } } BLI_edgehashIterator_free(ehi); /*map new vertices to faces*/ for (i = 0, u = 0; i < totface; i++) { MFace source; int orig_v4; if (facepa[i] != totpart) { pa = pars + facepa[i]; if (pa->alive == PARS_UNBORN && (emd->flag & eExplodeFlag_Unborn) == 0) { continue; } if (pa->alive == PARS_ALIVE && (emd->flag & eExplodeFlag_Alive) == 0) { continue; } if (pa->alive == PARS_DEAD && (emd->flag & eExplodeFlag_Dead) == 0) { continue; } } source = mesh->mface[i]; mf = &explode->mface[u]; orig_v4 = source.v4; if (facepa[i] != totpart && cfra < pa->time) { mindex = totvert + totpart; } else { mindex = totvert + facepa[i]; } source.v1 = edgecut_get(vertpahash, source.v1, mindex); source.v2 = edgecut_get(vertpahash, source.v2, mindex); source.v3 = edgecut_get(vertpahash, source.v3, mindex); if (source.v4) { source.v4 = edgecut_get(vertpahash, source.v4, mindex); } CustomData_copy_data(&mesh->fdata, &explode->fdata, i, u, 1); *mf = source; /* override uv channel for particle age */ if (mtface) { float age = (cfra - pa->time) / pa->lifetime; /* Clamp to this range to avoid flipping to the other side of the coordinates. */ CLAMP(age, 0.001f, 0.999f); mtf = mtface + u; mtf->uv[0][0] = mtf->uv[1][0] = mtf->uv[2][0] = mtf->uv[3][0] = age; mtf->uv[0][1] = mtf->uv[1][1] = mtf->uv[2][1] = mtf->uv[3][1] = 0.5f; } test_index_face(mf, &explode->fdata, u, (orig_v4 ? 4 : 3)); u++; } /* cleanup */ BLI_edgehash_free(vertpahash, NULL); /* finalization */ BKE_mesh_calc_edges_tessface(explode); BKE_mesh_convert_mfaces_to_mpolys(explode); explode->runtime.cd_dirty_vert |= CD_MASK_NORMAL; if (psmd->psys->lattice_deform_data) { end_latt_deform(psmd->psys->lattice_deform_data); psmd->psys->lattice_deform_data = NULL; } return explode; }
static Mesh *cutEdges(ExplodeModifierData *emd, Mesh *mesh) { Mesh *split_m; MFace *mf = NULL, *df1 = NULL; MFace *mface = mesh->mface; MVert *dupve, *mv; EdgeHash *edgehash; EdgeHashIterator *ehi; int totvert = mesh->totvert; int totface = mesh->totface; int *facesplit = MEM_calloc_arrayN(totface, sizeof(int), "explode_facesplit"); int *vertpa = MEM_calloc_arrayN(totvert, sizeof(int), "explode_vertpa2"); int *facepa = emd->facepa; int *fs, totesplit = 0, totfsplit = 0, curdupface = 0; int i, v1, v2, v3, v4, esplit, v[4] = {0, 0, 0, 0}, /* To quite gcc barking... */ uv[4] = {0, 0, 0, 0}; /* To quite gcc barking... */ int numlayer; unsigned int ed_v1, ed_v2; edgehash = BLI_edgehash_new(__func__); /* recreate vertpa from facepa calculation */ for (i = 0, mf = mface; i < totface; i++, mf++) { vertpa[mf->v1] = facepa[i]; vertpa[mf->v2] = facepa[i]; vertpa[mf->v3] = facepa[i]; if (mf->v4) { vertpa[mf->v4] = facepa[i]; } } /* mark edges for splitting and how to split faces */ for (i = 0, mf = mface, fs = facesplit; i < totface; i++, mf++, fs++) { v1 = vertpa[mf->v1]; v2 = vertpa[mf->v2]; v3 = vertpa[mf->v3]; if (v1 != v2) { BLI_edgehash_reinsert(edgehash, mf->v1, mf->v2, NULL); (*fs) |= 1; } if (v2 != v3) { BLI_edgehash_reinsert(edgehash, mf->v2, mf->v3, NULL); (*fs) |= 2; } if (mf->v4) { v4 = vertpa[mf->v4]; if (v3 != v4) { BLI_edgehash_reinsert(edgehash, mf->v3, mf->v4, NULL); (*fs) |= 4; } if (v1 != v4) { BLI_edgehash_reinsert(edgehash, mf->v1, mf->v4, NULL); (*fs) |= 8; } /* mark center vertex as a fake edge split */ if (*fs == 15) { BLI_edgehash_reinsert(edgehash, mf->v1, mf->v3, NULL); } } else { (*fs) |= 16; /* mark face as tri */ if (v1 != v3) { BLI_edgehash_reinsert(edgehash, mf->v1, mf->v3, NULL); (*fs) |= 4; } } } /* count splits & create indexes for new verts */ ehi = BLI_edgehashIterator_new(edgehash); totesplit = totvert; for (; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) { BLI_edgehashIterator_setValue(ehi, POINTER_FROM_INT(totesplit)); totesplit++; } BLI_edgehashIterator_free(ehi); /* count new faces due to splitting */ for (i = 0, fs = facesplit; i < totface; i++, fs++) { totfsplit += add_faces[*fs]; } split_m = BKE_mesh_new_nomain_from_template(mesh, totesplit, 0, totface + totfsplit, 0, 0); numlayer = CustomData_number_of_layers(&split_m->fdata, CD_MTFACE); /* copy new faces & verts (is it really this painful with custom data??) */ for (i = 0; i < totvert; i++) { MVert source; MVert *dest; source = mesh->mvert[i]; dest = &split_m->mvert[i]; CustomData_copy_data(&mesh->vdata, &split_m->vdata, i, i, 1); *dest = source; } /* override original facepa (original pointer is saved in caller function) */ /* BMESH_TODO, (totfsplit * 2) over allocation is used since the quads are * later interpreted as tri's, for this to work right I think we probably * have to stop using tessface - campbell */ facepa = MEM_calloc_arrayN((totface + (totfsplit * 2)), sizeof(int), "explode_facepa"); // memcpy(facepa, emd->facepa, totface*sizeof(int)); emd->facepa = facepa; /* create new verts */ ehi = BLI_edgehashIterator_new(edgehash); for (; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) { BLI_edgehashIterator_getKey(ehi, &ed_v1, &ed_v2); esplit = POINTER_AS_INT(BLI_edgehashIterator_getValue(ehi)); mv = &split_m->mvert[ed_v2]; dupve = &split_m->mvert[esplit]; CustomData_copy_data(&split_m->vdata, &split_m->vdata, ed_v2, esplit, 1); *dupve = *mv; mv = &split_m->mvert[ed_v1]; mid_v3_v3v3(dupve->co, dupve->co, mv->co); } BLI_edgehashIterator_free(ehi); /* create new faces */ curdupface = 0; //=totface; // curdupin=totesplit; for (i = 0, fs = facesplit; i < totface; i++, fs++) { mf = &mesh->mface[i]; switch (*fs) { case 3: case 10: case 11: case 15: SET_VERTS(1, 2, 3, 4); break; case 5: case 6: case 7: SET_VERTS(2, 3, 4, 1); break; case 9: case 13: SET_VERTS(4, 1, 2, 3); break; case 12: case 14: SET_VERTS(3, 4, 1, 2); break; case 21: case 23: SET_VERTS(1, 2, 3, 4); break; case 19: SET_VERTS(2, 3, 1, 4); break; case 22: SET_VERTS(3, 1, 2, 4); break; } switch (*fs) { case 3: case 6: case 9: case 12: remap_faces_3_6_9_12( mesh, split_m, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2], v[3]); if (numlayer) { remap_uvs_3_6_9_12(mesh, split_m, numlayer, i, curdupface, uv[0], uv[1], uv[2], uv[3]); } break; case 5: case 10: remap_faces_5_10( mesh, split_m, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2], v[3]); if (numlayer) { remap_uvs_5_10(mesh, split_m, numlayer, i, curdupface, uv[0], uv[1], uv[2], uv[3]); } break; case 15: remap_faces_15( mesh, split_m, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2], v[3]); if (numlayer) { remap_uvs_15(mesh, split_m, numlayer, i, curdupface, uv[0], uv[1], uv[2], uv[3]); } break; case 7: case 11: case 13: case 14: remap_faces_7_11_13_14( mesh, split_m, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2], v[3]); if (numlayer) { remap_uvs_7_11_13_14(mesh, split_m, numlayer, i, curdupface, uv[0], uv[1], uv[2], uv[3]); } break; case 19: case 21: case 22: remap_faces_19_21_22( mesh, split_m, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2]); if (numlayer) { remap_uvs_19_21_22(mesh, split_m, numlayer, i, curdupface, uv[0], uv[1], uv[2]); } break; case 23: remap_faces_23( mesh, split_m, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2]); if (numlayer) { remap_uvs_23(mesh, split_m, numlayer, i, curdupface, uv[0], uv[1], uv[2]); } break; case 0: case 16: df1 = get_dface(mesh, split_m, curdupface, i, mf); facepa[curdupface] = vertpa[mf->v1]; if (df1->v4) { df1->flag |= ME_FACE_SEL; } else { df1->flag &= ~ME_FACE_SEL; } break; } curdupface += add_faces[*fs] + 1; } for (i = 0; i < curdupface; i++) { mf = &split_m->mface[i]; test_index_face(mf, &split_m->fdata, i, ((mf->flag & ME_FACE_SEL) ? 4 : 3)); } BLI_edgehash_free(edgehash, NULL); MEM_freeN(facesplit); MEM_freeN(vertpa); BKE_mesh_calc_edges_tessface(split_m); BKE_mesh_convert_mfaces_to_mpolys(split_m); return split_m; }