static void undoMesh_to_editMesh(void *umv, void *emv) { EditMesh *em= (EditMesh *)emv; UndoMesh *um= (UndoMesh *)umv; EditVert *eve, **evar=NULL; EditEdge *eed; EditFace *efa; EditSelection *ese; EditVertC *evec; EditEdgeC *eedc; EditFaceC *efac; EditSelectionC *esec; int a=0; free_editMesh(em); /* malloc blocks */ memset(em, 0, sizeof(EditMesh)); em->selectmode = um->selectmode; em->shapenr = um->shapenr; init_editmesh_fastmalloc(em, um->totvert, um->totedge, um->totface); CustomData_free(&em->vdata, 0); CustomData_free(&em->edata, 0); CustomData_free(&em->fdata, 0); CustomData_copy(&um->vdata, &em->vdata, CD_MASK_EDITMESH, CD_CALLOC, 0); CustomData_copy(&um->edata, &em->edata, CD_MASK_EDITMESH, CD_CALLOC, 0); CustomData_copy(&um->fdata, &em->fdata, CD_MASK_EDITMESH, CD_CALLOC, 0); /* now copy vertices */ if(um->totvert) evar= MEM_mallocN(um->totvert*sizeof(EditVert *), "vertex ar"); for(a=0, evec= um->verts; a<um->totvert; a++, evec++) { eve= addvertlist(em, evec->co, NULL); evar[a]= eve; copy_v3_v3(eve->no, evec->no); eve->f= evec->f; eve->h= evec->h; eve->keyindex= evec->keyindex; eve->bweight= ((float)evec->bweight)/255.0f; CustomData_to_em_block(&um->vdata, &em->vdata, a, &eve->data); } /* copy edges */ for(a=0, eedc= um->edges; a<um->totedge; a++, eedc++) { eed= addedgelist(em, evar[eedc->v1], evar[eedc->v2], NULL); eed->f= eedc->f; eed->h= eedc->h; eed->seam= eedc->seam; eed->sharp= eedc->sharp; eed->fgoni= eedc->fgoni; eed->crease= ((float)eedc->crease)/255.0f; eed->bweight= ((float)eedc->bweight)/255.0f; CustomData_to_em_block(&um->edata, &em->edata, a, &eed->data); } /* copy faces */ for(a=0, efac= um->faces; a<um->totface; a++, efac++) { if(efac->v4 != -1) efa= addfacelist(em, evar[efac->v1], evar[efac->v2], evar[efac->v3], evar[efac->v4], NULL, NULL); else efa= addfacelist(em, evar[efac->v1], evar[efac->v2], evar[efac->v3], NULL, NULL ,NULL); efa->mat_nr= efac->mat_nr; efa->flag= efac->flag; efa->f= efac->f; efa->h= efac->h; efa->fgonf= efac->fgonf; CustomData_to_em_block(&um->fdata, &em->fdata, a, &efa->data); } end_editmesh_fastmalloc(); if(evar) MEM_freeN(evar); em->totvert = um->totvert; em->totedge = um->totedge; em->totface = um->totface; /*restore stored editselections*/ if(um->totsel){ EM_init_index_arrays(em, 1,1,1); for(a=0, esec= um->selected; a<um->totsel; a++, esec++){ ese = MEM_callocN(sizeof(EditSelection), "Edit Selection"); ese->type = esec->type; if(ese->type == EDITVERT) ese->data = EM_get_vert_for_index(esec->index); else if(ese->type == EDITEDGE) ese->data = EM_get_edge_for_index(esec->index); else if(ese->type == EDITFACE) ese->data = EM_get_face_for_index(esec->index); BLI_addtail(&(em->selected),ese); } EM_free_index_arrays(); } /* restore total selections */ EM_nvertices_selected(em); EM_nedges_selected(em); EM_nfaces_selected(em); }
/* do not free mesh itself */ void free_mesh(Mesh *me) { unlink_mesh(me); if(me->pv) { if(me->pv->vert_map) MEM_freeN(me->pv->vert_map); if(me->pv->edge_map) MEM_freeN(me->pv->edge_map); if(me->pv->old_faces) MEM_freeN(me->pv->old_faces); if(me->pv->old_edges) MEM_freeN(me->pv->old_edges); me->totvert= me->pv->totvert; me->totedge= me->pv->totedge; me->totface= me->pv->totface; MEM_freeN(me->pv); } CustomData_free(&me->vdata, me->totvert); CustomData_free(&me->edata, me->totedge); CustomData_free(&me->fdata, me->totface); if(me->adt) { BKE_free_animdata(&me->id); me->adt= NULL; } if(me->mat) MEM_freeN(me->mat); if(me->bb) MEM_freeN(me->bb); if(me->mselect) MEM_freeN(me->mselect); if(me->edit_mesh) MEM_freeN(me->edit_mesh); }
static void free_undoMesh(void *umv) { UndoMesh *um= umv; if(um->verts) MEM_freeN(um->verts); if(um->edges) MEM_freeN(um->edges); if(um->faces) MEM_freeN(um->faces); if(um->selected) MEM_freeN(um->selected); CustomData_free(&um->vdata, um->totvert); CustomData_free(&um->edata, um->totedge); CustomData_free(&um->fdata, um->totface); MEM_freeN(um); }
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; }
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; }
// ================================================================= // 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; }
/* do not free mesh itself */ void BKE_mesh_free(Mesh *me, int unlink) { if (unlink) BKE_mesh_unlink(me); CustomData_free(&me->vdata, me->totvert); CustomData_free(&me->edata, me->totedge); CustomData_free(&me->fdata, me->totface); CustomData_free(&me->ldata, me->totloop); CustomData_free(&me->pdata, me->totpoly); if (me->adt) { BKE_free_animdata(&me->id); me->adt = NULL; } if (me->mat) MEM_freeN(me->mat); if (me->bb) MEM_freeN(me->bb); if (me->mselect) MEM_freeN(me->mselect); if (me->edit_btmesh) MEM_freeN(me->edit_btmesh); }
static void mesh_calc_edges(Mesh *mesh) { CustomData edata; EdgeHashIterator *ehi; MFace *mf = mesh->mface; MEdge *med; EdgeHash *eh = BLI_edgehash_new(); int i, *index, totedge, totface = mesh->totface; for (i = 0; i < totface; i++, mf++) { if (!BLI_edgehash_haskey(eh, mf->v1, mf->v2)) BLI_edgehash_insert(eh, mf->v1, mf->v2, NULL); if (!BLI_edgehash_haskey(eh, mf->v2, mf->v3)) BLI_edgehash_insert(eh, mf->v2, mf->v3, NULL); if (mf->v4) { if (!BLI_edgehash_haskey(eh, mf->v3, mf->v4)) BLI_edgehash_insert(eh, mf->v3, mf->v4, NULL); if (!BLI_edgehash_haskey(eh, mf->v4, mf->v1)) BLI_edgehash_insert(eh, mf->v4, mf->v1, NULL); } else { if (!BLI_edgehash_haskey(eh, mf->v3, mf->v1)) BLI_edgehash_insert(eh, mf->v3, mf->v1, NULL); } } totedge = BLI_edgehash_size(eh); /* write new edges into a temporary CustomData */ memset(&edata, 0, sizeof(edata)); CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, NULL, totedge); ehi = BLI_edgehashIterator_new(eh); med = CustomData_get_layer(&edata, CD_MEDGE); for(i = 0; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi), ++i, ++med, ++index) { BLI_edgehashIterator_getKey(ehi, (int*)&med->v1, (int*)&med->v2); med->flag = ME_EDGEDRAW|ME_EDGERENDER; } BLI_edgehashIterator_free(ehi); /* free old CustomData and assign new one */ CustomData_free(&mesh->edata, mesh->totedge); mesh->edata = edata; mesh->totedge = totedge; mesh->medge = CustomData_get_layer(&mesh->edata, CD_MEDGE); BLI_edgehash_free(eh, NULL); }
void BME_free_mesh(BME_Mesh *bm) { BME_Vert *v; BME_Edge *e; BME_Loop *l; BME_Poly *f; for(v=bm->verts.first; v; v=v->next) CustomData_bmesh_free_block(&bm->vdata, &v->data); for(e=bm->edges.first; e; e=e->next) CustomData_bmesh_free_block(&bm->edata, &e->data); for(f=bm->polys.first; f; f=f->next){ CustomData_bmesh_free_block(&bm->pdata, &f->data); l = f->loopbase; do{ CustomData_bmesh_free_block(&bm->ldata, &l->data); l = l->next; }while(l!=f->loopbase); } /*Free custom data pools, This should probably go in CustomData_free?*/ if(bm->vdata.totlayer) BLI_mempool_destroy(bm->vdata.pool); if(bm->edata.totlayer) BLI_mempool_destroy(bm->edata.pool); if(bm->ldata.totlayer) BLI_mempool_destroy(bm->ldata.pool); if(bm->pdata.totlayer) BLI_mempool_destroy(bm->pdata.pool); /*free custom data*/ CustomData_free(&bm->vdata,0); CustomData_free(&bm->edata,0); CustomData_free(&bm->ldata,0); CustomData_free(&bm->pdata,0); /*destroy element pools*/ BLI_mempool_destroy(bm->vpool); BLI_mempool_destroy(bm->epool); BLI_mempool_destroy(bm->ppool); BLI_mempool_destroy(bm->lpool); MEM_freeN(bm); }
static void mesh_tessface_clear_intern(Mesh *mesh, int free_customdata) { if (free_customdata) { CustomData_free(&mesh->fdata, mesh->totface); } else { CustomData_reset(&mesh->fdata); } mesh->mface = NULL; mesh->mtface = NULL; mesh->mcol = NULL; mesh->totface = 0; }
/** * Calculate edges from polygons * * \param mesh The mesh to add edges into * \param update When true create new edges co-exist */ void BKE_mesh_calc_edges(Mesh *mesh, bool update, const bool select) { CustomData edata; EdgeHashIterator *ehi; MPoly *mp; MEdge *med, *med_orig; EdgeHash *eh = BLI_edgehash_new(); int i, totedge, totpoly = mesh->totpoly; int med_index; /* select for newly created meshes which are selected [#25595] */ const short ed_flag = (ME_EDGEDRAW | ME_EDGERENDER) | (select ? SELECT : 0); if (mesh->totedge == 0) update = false; if (update) { /* assume existing edges are valid * useful when adding more faces and generating edges from them */ med = mesh->medge; for (i = 0; i < mesh->totedge; i++, med++) BLI_edgehash_insert(eh, med->v1, med->v2, med); } /* mesh loops (bmesh only) */ for (mp = mesh->mpoly, i = 0; i < totpoly; mp++, i++) { MLoop *l = &mesh->mloop[mp->loopstart]; int j, l_prev = (l + (mp->totloop - 1))->v; for (j = 0; j < mp->totloop; j++, l++) { if (!BLI_edgehash_haskey(eh, l_prev, l->v)) { BLI_edgehash_insert(eh, l_prev, l->v, NULL); } l_prev = l->v; } } totedge = BLI_edgehash_size(eh); /* write new edges into a temporary CustomData */ CustomData_reset(&edata); CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, NULL, totedge); med = CustomData_get_layer(&edata, CD_MEDGE); for (ehi = BLI_edgehashIterator_new(eh), i = 0; BLI_edgehashIterator_isDone(ehi) == FALSE; BLI_edgehashIterator_step(ehi), ++i, ++med) { if (update && (med_orig = BLI_edgehashIterator_getValue(ehi))) { *med = *med_orig; /* copy from the original */ } else { BLI_edgehashIterator_getKey(ehi, &med->v1, &med->v2); med->flag = ed_flag; } /* store the new edge index in the hash value */ BLI_edgehashIterator_setValue(ehi, SET_INT_IN_POINTER(i)); } BLI_edgehashIterator_free(ehi); if (mesh->totpoly) { /* second pass, iterate through all loops again and assign * the newly created edges to them. */ for (mp = mesh->mpoly, i = 0; i < mesh->totpoly; mp++, i++) { MLoop *l = &mesh->mloop[mp->loopstart]; MLoop *l_prev = (l + (mp->totloop - 1)); int j; for (j = 0; j < mp->totloop; j++, l++) { /* lookup hashed edge index */ med_index = GET_INT_FROM_POINTER(BLI_edgehash_lookup(eh, l_prev->v, l->v)); l_prev->e = med_index; l_prev = l; } } } /* free old CustomData and assign new one */ CustomData_free(&mesh->edata, mesh->totedge); mesh->edata = edata; mesh->totedge = totedge; mesh->medge = CustomData_get_layer(&mesh->edata, CD_MEDGE); BLI_edgehash_free(eh, NULL); }
/** * \brief Mesh -> BMesh * * \warning This function doesn't calculate face normals. */ void BM_mesh_bm_from_me(BMesh *bm, Mesh *me, const bool calc_face_normal, const bool set_key, int act_key_nr) { MVert *mvert; MEdge *medge; MLoop *mloop; MPoly *mp; KeyBlock *actkey, *block; BMVert *v, **vtable = NULL; BMEdge *e, **etable = NULL; BMFace *f; float (*keyco)[3] = NULL; int *keyi; int totuv, i, j; int cd_vert_bweight_offset; int cd_edge_bweight_offset; int cd_edge_crease_offset; /* free custom data */ /* this isnt needed in most cases but do just incase */ CustomData_free(&bm->vdata, bm->totvert); CustomData_free(&bm->edata, bm->totedge); CustomData_free(&bm->ldata, bm->totloop); CustomData_free(&bm->pdata, bm->totface); if (!me || !me->totvert) { if (me) { /*no verts? still copy customdata layout*/ CustomData_copy(&me->vdata, &bm->vdata, CD_MASK_BMESH, CD_ASSIGN, 0); CustomData_copy(&me->edata, &bm->edata, CD_MASK_BMESH, CD_ASSIGN, 0); CustomData_copy(&me->ldata, &bm->ldata, CD_MASK_BMESH, CD_ASSIGN, 0); CustomData_copy(&me->pdata, &bm->pdata, CD_MASK_BMESH, CD_ASSIGN, 0); CustomData_bmesh_init_pool(&bm->vdata, me->totvert, BM_VERT); CustomData_bmesh_init_pool(&bm->edata, me->totedge, BM_EDGE); CustomData_bmesh_init_pool(&bm->ldata, me->totloop, BM_LOOP); CustomData_bmesh_init_pool(&bm->pdata, me->totpoly, BM_FACE); } return; /* sanity check */ } vtable = MEM_mallocN(sizeof(void **) * me->totvert, "mesh to bmesh vtable"); CustomData_copy(&me->vdata, &bm->vdata, CD_MASK_BMESH, CD_CALLOC, 0); CustomData_copy(&me->edata, &bm->edata, CD_MASK_BMESH, CD_CALLOC, 0); CustomData_copy(&me->ldata, &bm->ldata, CD_MASK_BMESH, CD_CALLOC, 0); CustomData_copy(&me->pdata, &bm->pdata, CD_MASK_BMESH, CD_CALLOC, 0); /* make sure uv layer names are consisten */ totuv = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY); for (i = 0; i < totuv; i++) { int li = CustomData_get_layer_index_n(&bm->pdata, CD_MTEXPOLY, i); CustomData_set_layer_name(&bm->ldata, CD_MLOOPUV, i, bm->pdata.layers[li].name); } if ((act_key_nr != 0) && (me->key != NULL)) { actkey = BLI_findlink(&me->key->block, act_key_nr - 1); } else { actkey = NULL; } if (me->key) { CustomData_add_layer(&bm->vdata, CD_SHAPE_KEYINDEX, CD_ASSIGN, NULL, 0); /* check if we need to generate unique ids for the shapekeys. * this also exists in the file reading code, but is here for * a sanity check */ if (!me->key->uidgen) { fprintf(stderr, "%s had to generate shape key uid's in a situation we shouldn't need to! " "(bmesh internal error)\n", __func__); me->key->uidgen = 1; for (block = me->key->block.first; block; block = block->next) { block->uid = me->key->uidgen++; } } if (actkey && actkey->totelem == me->totvert) { keyco = actkey->data; bm->shapenr = act_key_nr; } for (i = 0, block = me->key->block.first; block; block = block->next, i++) { CustomData_add_layer_named(&bm->vdata, CD_SHAPEKEY, CD_ASSIGN, NULL, 0, block->name); j = CustomData_get_layer_index_n(&bm->vdata, CD_SHAPEKEY, i); bm->vdata.layers[j].uid = block->uid; } } CustomData_bmesh_init_pool(&bm->vdata, me->totvert, BM_VERT); CustomData_bmesh_init_pool(&bm->edata, me->totedge, BM_EDGE); CustomData_bmesh_init_pool(&bm->ldata, me->totloop, BM_LOOP); CustomData_bmesh_init_pool(&bm->pdata, me->totpoly, BM_FACE); BM_mesh_cd_flag_apply(bm, me->cd_flag); cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT); cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT); cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE); for (i = 0, mvert = me->mvert; i < me->totvert; i++, mvert++) { v = vtable[i] = BM_vert_create(bm, keyco && set_key ? keyco[i] : mvert->co, NULL, BM_CREATE_SKIP_CD); BM_elem_index_set(v, i); /* set_ok */ /* transfer flag */ v->head.hflag = BM_vert_flag_from_mflag(mvert->flag & ~SELECT); /* this is necessary for selection counts to work properly */ if (mvert->flag & SELECT) { BM_vert_select_set(bm, v, true); } normal_short_to_float_v3(v->no, mvert->no); /* Copy Custom Data */ CustomData_to_bmesh_block(&me->vdata, &bm->vdata, i, &v->head.data, true); if (cd_vert_bweight_offset != -1) BM_ELEM_CD_SET_FLOAT(v, cd_vert_bweight_offset, (float)mvert->bweight / 255.0f); /* set shapekey data */ if (me->key) { /* set shape key original index */ keyi = CustomData_bmesh_get(&bm->vdata, v->head.data, CD_SHAPE_KEYINDEX); if (keyi) { *keyi = i; } for (block = me->key->block.first, j = 0; block; block = block->next, j++) { float *co = CustomData_bmesh_get_n(&bm->vdata, v->head.data, CD_SHAPEKEY, j); if (co) { copy_v3_v3(co, ((float *)block->data) + 3 * i); } } } } bm->elem_index_dirty &= ~BM_VERT; /* added in order, clear dirty flag */ if (!me->totedge) { MEM_freeN(vtable); return; } etable = MEM_mallocN(sizeof(void **) * me->totedge, "mesh to bmesh etable"); medge = me->medge; for (i = 0; i < me->totedge; i++, medge++) { e = etable[i] = BM_edge_create(bm, vtable[medge->v1], vtable[medge->v2], NULL, BM_CREATE_SKIP_CD); BM_elem_index_set(e, i); /* set_ok */ /* transfer flags */ e->head.hflag = BM_edge_flag_from_mflag(medge->flag & ~SELECT); /* this is necessary for selection counts to work properly */ if (medge->flag & SELECT) { BM_edge_select_set(bm, e, true); } /* Copy Custom Data */ CustomData_to_bmesh_block(&me->edata, &bm->edata, i, &e->head.data, true); if (cd_edge_bweight_offset != -1) BM_ELEM_CD_SET_FLOAT(e, cd_edge_bweight_offset, (float)medge->bweight / 255.0f); if (cd_edge_crease_offset != -1) BM_ELEM_CD_SET_FLOAT(e, cd_edge_crease_offset, (float)medge->crease / 255.0f); } bm->elem_index_dirty &= ~BM_EDGE; /* added in order, clear dirty flag */ mloop = me->mloop; mp = me->mpoly; for (i = 0; i < me->totpoly; i++, mp++) { BMLoop *l_iter; BMLoop *l_first; f = bm_face_create_from_mpoly(mp, mloop + mp->loopstart, bm, vtable, etable); if (UNLIKELY(f == NULL)) { printf("%s: Warning! Bad face in mesh" " \"%s\" at index %d!, skipping\n", __func__, me->id.name + 2, i); continue; } /* don't use 'i' since we may have skipped the face */ BM_elem_index_set(f, bm->totface - 1); /* set_ok */ /* transfer flag */ f->head.hflag = BM_face_flag_from_mflag(mp->flag & ~ME_FACE_SEL); /* this is necessary for selection counts to work properly */ if (mp->flag & ME_FACE_SEL) { BM_face_select_set(bm, f, true); } f->mat_nr = mp->mat_nr; if (i == me->act_face) bm->act_face = f; j = mp->loopstart; l_iter = l_first = BM_FACE_FIRST_LOOP(f); do { /* Save index of correspsonding MLoop */ CustomData_to_bmesh_block(&me->ldata, &bm->ldata, j++, &l_iter->head.data, true); } while ((l_iter = l_iter->next) != l_first); /* Copy Custom Data */ CustomData_to_bmesh_block(&me->pdata, &bm->pdata, i, &f->head.data, true); if (calc_face_normal) { BM_face_normal_update(f); } } bm->elem_index_dirty &= ~BM_FACE; /* added in order, clear dirty flag */ if (me->mselect && me->totselect != 0) { BMVert **vert_array = MEM_mallocN(sizeof(BMVert *) * bm->totvert, "VSelConv"); BMEdge **edge_array = MEM_mallocN(sizeof(BMEdge *) * bm->totedge, "ESelConv"); BMFace **face_array = MEM_mallocN(sizeof(BMFace *) * bm->totface, "FSelConv"); MSelect *msel; #pragma omp parallel sections if (bm->totvert + bm->totedge + bm->totface >= BM_OMP_LIMIT) { #pragma omp section { BM_iter_as_array(bm, BM_VERTS_OF_MESH, NULL, (void **)vert_array, bm->totvert); } #pragma omp section { BM_iter_as_array(bm, BM_EDGES_OF_MESH, NULL, (void **)edge_array, bm->totedge); } #pragma omp section { BM_iter_as_array(bm, BM_FACES_OF_MESH, NULL, (void **)face_array, bm->totface); } } for (i = 0, msel = me->mselect; i < me->totselect; i++, msel++) { switch (msel->type) { case ME_VSEL: BM_select_history_store(bm, (BMElem *)vert_array[msel->index]); break; case ME_ESEL: BM_select_history_store(bm, (BMElem *)edge_array[msel->index]); break; case ME_FSEL: BM_select_history_store(bm, (BMElem *)face_array[msel->index]); break; } } MEM_freeN(vert_array); MEM_freeN(edge_array); MEM_freeN(face_array); } else { me->totselect = 0; if (me->mselect) { MEM_freeN(me->mselect); me->mselect = NULL; } } MEM_freeN(vtable); MEM_freeN(etable); }
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; }
/* makes Mesh out of editmesh */ void load_editMesh(Scene *scene, Object *obedit) { Mesh *me= obedit->data; MVert *mvert, *oldverts; MEdge *medge; MFace *mface; MSelect *mselect; EditMesh *em= me->edit_mesh; EditVert *eve; EditFace *efa, *efa_act; EditEdge *eed; EditSelection *ese; float *fp, *newkey, *oldkey; int i, a, ototvert; /* this one also tests of edges are not in faces: */ /* eed->f2==0: not in face, f2==1: draw it */ /* eed->f1 : flag for dynaface (cylindertest, old engine) */ /* eve->f1 : flag for dynaface (sphere test, old engine) */ /* eve->f2 : being used in vertexnormals */ edge_drawflags(me, em); EM_stats_update(em); /* new Vertex block */ if(em->totvert==0) mvert= NULL; else mvert= MEM_callocN(em->totvert*sizeof(MVert), "loadeditMesh vert"); /* new Edge block */ if(em->totedge==0) medge= NULL; else medge= MEM_callocN(em->totedge*sizeof(MEdge), "loadeditMesh edge"); /* new Face block */ if(em->totface==0) mface= NULL; else mface= MEM_callocN(em->totface*sizeof(MFace), "loadeditMesh face"); /* lets save the old verts just in case we are actually working on * a key ... we now do processing of the keys at the end */ oldverts= me->mvert; ototvert= me->totvert; /* don't free this yet */ CustomData_set_layer(&me->vdata, CD_MVERT, NULL); /* free custom data */ CustomData_free(&me->vdata, me->totvert); CustomData_free(&me->edata, me->totedge); CustomData_free(&me->fdata, me->totface); /* add new custom data */ me->totvert= em->totvert; me->totedge= em->totedge; me->totface= em->totface; CustomData_copy(&em->vdata, &me->vdata, CD_MASK_MESH, CD_CALLOC, me->totvert); CustomData_copy(&em->edata, &me->edata, CD_MASK_MESH, CD_CALLOC, me->totedge); CustomData_copy(&em->fdata, &me->fdata, CD_MASK_MESH, CD_CALLOC, me->totface); CustomData_add_layer(&me->vdata, CD_MVERT, CD_ASSIGN, mvert, me->totvert); CustomData_add_layer(&me->edata, CD_MEDGE, CD_ASSIGN, medge, me->totedge); CustomData_add_layer(&me->fdata, CD_MFACE, CD_ASSIGN, mface, me->totface); mesh_update_customdata_pointers(me); /* the vertices, use ->tmp.l as counter */ eve= em->verts.first; a= 0; while(eve) { VECCOPY(mvert->co, eve->co); /* vertex normal */ normal_float_to_short_v3(mvert->no, eve->no); /* note: it used to remove me->dvert when it was not in use, cancelled that... annoying when you have a fresh vgroup */ CustomData_from_em_block(&em->vdata, &me->vdata, eve->data, a); eve->tmp.l = a++; /* counter */ mvert->flag= 0; mvert->flag |= (eve->f & SELECT); if (eve->h) mvert->flag |= ME_HIDE; mvert->bweight= (char)(255.0f*eve->bweight); eve= eve->next; mvert++; } /* the edges */ a= 0; eed= em->edges.first; while(eed) { medge->v1= (unsigned int) eed->v1->tmp.l; medge->v2= (unsigned int) eed->v2->tmp.l; medge->flag= (eed->f & SELECT) | ME_EDGERENDER; if(eed->f2<2) medge->flag |= ME_EDGEDRAW; if(eed->f2==0) medge->flag |= ME_LOOSEEDGE; if(eed->sharp) medge->flag |= ME_SHARP; if(eed->seam) medge->flag |= ME_SEAM; if(eed->h & EM_FGON) medge->flag |= ME_FGON; // different defines yes if(eed->h & 1) medge->flag |= ME_HIDE; medge->crease= (char)(255.0f*eed->crease); medge->bweight= (char)(255.0f*eed->bweight); CustomData_from_em_block(&em->edata, &me->edata, eed->data, a); eed->tmp.l = a++; medge++; eed= eed->next; } /* the faces */ a = 0; efa= em->faces.first; efa_act= EM_get_actFace(em, 0); i = 0; me->act_face = -1; while(efa) { mface= &((MFace *) me->mface)[i]; mface->v1= (unsigned int) efa->v1->tmp.l; mface->v2= (unsigned int) efa->v2->tmp.l; mface->v3= (unsigned int) efa->v3->tmp.l; if (efa->v4) mface->v4 = (unsigned int) efa->v4->tmp.l; mface->mat_nr= efa->mat_nr; mface->flag= efa->flag; /* bit 0 of flag is already taken for smooth... */ if(efa->h) { mface->flag |= ME_HIDE; mface->flag &= ~ME_FACE_SEL; } else { if(efa->f & 1) mface->flag |= ME_FACE_SEL; else mface->flag &= ~ME_FACE_SEL; } /* watch: efa->e1->f2==0 means loose edge */ if(efa->e1->f2==1) { efa->e1->f2= 2; } if(efa->e2->f2==1) { efa->e2->f2= 2; } if(efa->e3->f2==1) { efa->e3->f2= 2; } if(efa->e4 && efa->e4->f2==1) { efa->e4->f2= 2; } CustomData_from_em_block(&em->fdata, &me->fdata, efa->data, i); /* no index '0' at location 3 or 4 */ test_index_face(mface, &me->fdata, i, efa->v4?4:3); if (efa_act == efa) me->act_face = a; efa->tmp.l = a++; i++; efa= efa->next; } /* patch hook indices and vertex parents */ { Object *ob; ModifierData *md; EditVert **vertMap = NULL; int j; for (ob=G.main->object.first; ob; ob=ob->id.next) { if (ob->parent==obedit && ELEM(ob->partype, PARVERT1,PARVERT3)) { /* duplicate code from below, make it function later...? */ if (!vertMap) { vertMap = MEM_callocN(sizeof(*vertMap)*ototvert, "vertMap"); for (eve=em->verts.first; eve; eve=eve->next) { if (eve->keyindex!=-1) vertMap[eve->keyindex] = eve; } } if(ob->par1 < ototvert) { eve = vertMap[ob->par1]; if(eve) ob->par1= eve->tmp.l; } if(ob->par2 < ototvert) { eve = vertMap[ob->par2]; if(eve) ob->par2= eve->tmp.l; } if(ob->par3 < ototvert) { eve = vertMap[ob->par3]; if(eve) ob->par3= eve->tmp.l; } } if (ob->data==me) { for (md=ob->modifiers.first; md; md=md->next) { if (md->type==eModifierType_Hook) { HookModifierData *hmd = (HookModifierData*) md; if (!vertMap) { vertMap = MEM_callocN(sizeof(*vertMap)*ototvert, "vertMap"); for (eve=em->verts.first; eve; eve=eve->next) { if (eve->keyindex!=-1) vertMap[eve->keyindex] = eve; } } for (i=j=0; i<hmd->totindex; i++) { if(hmd->indexar[i] < ototvert) { eve = vertMap[hmd->indexar[i]]; if (eve) { hmd->indexar[j++] = eve->tmp.l; } } else j++; } hmd->totindex = j; } } } } if (vertMap) MEM_freeN(vertMap); } /* are there keys? */ if(me->key) { KeyBlock *currkey; KeyBlock *actkey= BLI_findlink(&me->key->block, em->shapenr-1); float (*ofs)[3] = NULL; /* editing the base key should update others */ if(me->key->type==KEY_RELATIVE && oldverts) { int act_is_basis = 0; /* find if this key is a basis for any others */ for(currkey = me->key->block.first; currkey; currkey= currkey->next) { if(em->shapenr-1 == currkey->relative) { act_is_basis = 1; break; } } if(act_is_basis) { /* active key is a base */ float (*fp)[3]= actkey->data; i=0; ofs= MEM_callocN(sizeof(float) * 3 * em->totvert, "currkey->data"); eve= em->verts.first; mvert = me->mvert; while(eve) { if(eve->keyindex>=0) { sub_v3_v3v3(ofs[i], mvert->co, fp[eve->keyindex]); } eve= eve->next; i++; mvert++; } } } /* Lets reorder the key data so that things line up roughly * with the way things were before editmode */ currkey = me->key->block.first; while(currkey) { int apply_offset = (ofs && (currkey != actkey) && (em->shapenr-1 == currkey->relative)); fp= newkey= MEM_callocN(me->key->elemsize*em->totvert, "currkey->data"); oldkey = currkey->data; eve= em->verts.first; i = 0; mvert = me->mvert; while(eve) { if (eve->keyindex >= 0 && eve->keyindex < currkey->totelem) { // valid old vertex if(currkey == actkey) { if(actkey == me->key->refkey) { VECCOPY(fp, mvert->co); } else { VECCOPY(fp, mvert->co); if(oldverts) { VECCOPY(mvert->co, oldverts[eve->keyindex].co); } } } else { if(oldkey) { VECCOPY(fp, oldkey + 3 * eve->keyindex); } } } else { VECCOPY(fp, mvert->co); } /* propagate edited basis offsets to other shapes */ if(apply_offset) { VECADD(fp, fp, ofs[i]); } fp+= 3; ++i; ++mvert; eve= eve->next; } currkey->totelem= em->totvert; if(currkey->data) MEM_freeN(currkey->data); currkey->data = newkey; currkey= currkey->next; } if(ofs) MEM_freeN(ofs); } if(oldverts) MEM_freeN(oldverts); i = 0; for(ese=em->selected.first; ese; ese=ese->next) i++; me->totselect = i; if(i==0) mselect= NULL; else mselect= MEM_callocN(i*sizeof(MSelect), "loadeditMesh selections"); if(me->mselect) MEM_freeN(me->mselect); me->mselect= mselect; for(ese=em->selected.first; ese; ese=ese->next){ mselect->type = ese->type; if(ese->type == EDITVERT) mselect->index = ((EditVert*)ese->data)->tmp.l; else if(ese->type == EDITEDGE) mselect->index = ((EditEdge*)ese->data)->tmp.l; else if(ese->type == EDITFACE) mselect->index = ((EditFace*)ese->data)->tmp.l; mselect++; } /* to be sure: clear ->tmp.l pointers */ eve= em->verts.first; while(eve) { eve->tmp.l = 0; eve= eve->next; } eed= em->edges.first; while(eed) { eed->tmp.l = 0; eed= eed->next; } efa= em->faces.first; while(efa) { efa->tmp.l = 0; efa= efa->next; } /* remake softbody of all users */ if(me->id.us>1) { Base *base; for(base= scene->base.first; base; base= base->next) if(base->object->data==me) base->object->recalc |= OB_RECALC_DATA; } mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL); /* topology could be changed, ensure mdisps are ok */ multires_topology_changed(scene, obedit); }
/* do not free editmesh itself here */ void free_editMesh(EditMesh *em) { if(em==NULL) return; if(em->verts.first) free_vertlist(em, &em->verts); if(em->edges.first) free_edgelist(em, &em->edges); if(em->faces.first) free_facelist(em, &em->faces); if(em->selected.first) BLI_freelistN(&(em->selected)); CustomData_free(&em->vdata, 0); CustomData_free(&em->fdata, 0); if(em->derivedFinal) { if (em->derivedFinal!=em->derivedCage) { em->derivedFinal->needsFree= 1; em->derivedFinal->release(em->derivedFinal); } em->derivedFinal= NULL; } if(em->derivedCage) { em->derivedCage->needsFree= 1; em->derivedCage->release(em->derivedCage); em->derivedCage= NULL; } /* DEBUG: hashtabs are slowest part of enter/exit editmode. here a testprint */ #if 0 if(em->hashedgetab) { HashEdge *he, *hen; int a, used=0, max=0, nr; he= em->hashedgetab; for(a=0; a<EDHASHSIZE; a++, he++) { if(he->eed) used++; hen= he->next; nr= 0; while(hen) { nr++; hen= hen->next; } if(max<nr) max= nr; } printf("hastab used %d max %d\n", used, max); } #endif if(em->hashedgetab) MEM_freeN(em->hashedgetab); em->hashedgetab= NULL; if(em->allverts) MEM_freeN(em->allverts); if(em->alledges) MEM_freeN(em->alledges); if(em->allfaces) MEM_freeN(em->allfaces); em->allverts= em->curvert= NULL; em->alledges= em->curedge= NULL; em->allfaces= em->curface= NULL; mesh_octree_table(NULL, NULL, NULL, 'e'); mesh_mirrtopo_table(NULL, 'e'); em->totvert= em->totedge= em->totface= 0; em->act_face = NULL; }
void BKE_mesh_calc_edges(Mesh *mesh, int update) { CustomData edata; EdgeHashIterator *ehi; MFace *mf = mesh->mface; MEdge *med, *med_orig; EdgeHash *eh = BLI_edgehash_new(); int i, totedge, totface = mesh->totface; if(mesh->totedge==0) update= 0; if(update) { /* assume existing edges are valid * useful when adding more faces and generating edges from them */ med= mesh->medge; for(i= 0; i<mesh->totedge; i++, med++) BLI_edgehash_insert(eh, med->v1, med->v2, med); } for (i = 0; i < totface; i++, mf++) { if (!BLI_edgehash_haskey(eh, mf->v1, mf->v2)) BLI_edgehash_insert(eh, mf->v1, mf->v2, NULL); if (!BLI_edgehash_haskey(eh, mf->v2, mf->v3)) BLI_edgehash_insert(eh, mf->v2, mf->v3, NULL); if (mf->v4) { if (!BLI_edgehash_haskey(eh, mf->v3, mf->v4)) BLI_edgehash_insert(eh, mf->v3, mf->v4, NULL); if (!BLI_edgehash_haskey(eh, mf->v4, mf->v1)) BLI_edgehash_insert(eh, mf->v4, mf->v1, NULL); } else { if (!BLI_edgehash_haskey(eh, mf->v3, mf->v1)) BLI_edgehash_insert(eh, mf->v3, mf->v1, NULL); } } totedge = BLI_edgehash_size(eh); /* write new edges into a temporary CustomData */ memset(&edata, 0, sizeof(edata)); CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, NULL, totedge); ehi = BLI_edgehashIterator_new(eh); med = CustomData_get_layer(&edata, CD_MEDGE); for(i = 0; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi), ++i, ++med) { if(update && (med_orig=BLI_edgehashIterator_getValue(ehi))) { *med= *med_orig; /* copy from the original */ } else { BLI_edgehashIterator_getKey(ehi, (int*)&med->v1, (int*)&med->v2); med->flag = ME_EDGEDRAW|ME_EDGERENDER|SELECT; /* select for newly created meshes which are selected [#25595] */ } } BLI_edgehashIterator_free(ehi); /* free old CustomData and assign new one */ CustomData_free(&mesh->edata, mesh->totedge); mesh->edata = edata; mesh->totedge = totedge; mesh->medge = CustomData_get_layer(&mesh->edata, CD_MEDGE); BLI_edgehash_free(eh, NULL); }
/* This is a Mesh-based copy of DM_to_mesh() */ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src, Mesh *mesh_dst, Object *ob, const CustomData_MeshMasks *mask, bool take_ownership) { /* mesh_src might depend on mesh_dst, so we need to do everything with a local copy */ /* TODO(Sybren): the above claim came from DM_to_mesh(); * check whether it is still true with Mesh */ Mesh tmp = *mesh_dst; int totvert, totedge /*, totface */ /* UNUSED */, totloop, totpoly; int did_shapekeys = 0; eCDAllocType alloctype = CD_DUPLICATE; if (take_ownership /* && dm->type == DM_TYPE_CDDM && dm->needsFree */) { bool has_any_referenced_layers = CustomData_has_referenced(&mesh_src->vdata) || CustomData_has_referenced(&mesh_src->edata) || CustomData_has_referenced(&mesh_src->ldata) || CustomData_has_referenced(&mesh_src->fdata) || CustomData_has_referenced(&mesh_src->pdata); if (!has_any_referenced_layers) { alloctype = CD_ASSIGN; } } CustomData_reset(&tmp.vdata); CustomData_reset(&tmp.edata); CustomData_reset(&tmp.fdata); CustomData_reset(&tmp.ldata); CustomData_reset(&tmp.pdata); BKE_mesh_ensure_normals(mesh_src); totvert = tmp.totvert = mesh_src->totvert; totedge = tmp.totedge = mesh_src->totedge; totloop = tmp.totloop = mesh_src->totloop; totpoly = tmp.totpoly = mesh_src->totpoly; tmp.totface = 0; CustomData_copy(&mesh_src->vdata, &tmp.vdata, mask->vmask, alloctype, totvert); CustomData_copy(&mesh_src->edata, &tmp.edata, mask->emask, alloctype, totedge); CustomData_copy(&mesh_src->ldata, &tmp.ldata, mask->lmask, alloctype, totloop); CustomData_copy(&mesh_src->pdata, &tmp.pdata, mask->pmask, alloctype, totpoly); tmp.cd_flag = mesh_src->cd_flag; tmp.runtime.deformed_only = mesh_src->runtime.deformed_only; if (CustomData_has_layer(&mesh_src->vdata, CD_SHAPEKEY)) { KeyBlock *kb; int uid; if (ob) { kb = BLI_findlink(&mesh_dst->key->block, ob->shapenr - 1); if (kb) { uid = kb->uid; } else { CLOG_ERROR(&LOG, "could not find active shapekey %d!", ob->shapenr - 1); uid = INT_MAX; } } else { /* if no object, set to INT_MAX so we don't mess up any shapekey layers */ uid = INT_MAX; } shapekey_layers_to_keyblocks(mesh_src, mesh_dst, uid); did_shapekeys = 1; } /* copy texture space */ if (ob) { BKE_mesh_texspace_copy_from_object(&tmp, ob); } /* not all DerivedMeshes store their verts/edges/faces in CustomData, so * we set them here in case they are missing */ /* TODO(Sybren): we could probably replace CD_ASSIGN with alloctype and * always directly pass mesh_src->mxxx, instead of using a ternary operator. */ if (!CustomData_has_layer(&tmp.vdata, CD_MVERT)) { CustomData_add_layer(&tmp.vdata, CD_MVERT, CD_ASSIGN, (alloctype == CD_ASSIGN) ? mesh_src->mvert : MEM_dupallocN(mesh_src->mvert), totvert); } if (!CustomData_has_layer(&tmp.edata, CD_MEDGE)) { CustomData_add_layer(&tmp.edata, CD_MEDGE, CD_ASSIGN, (alloctype == CD_ASSIGN) ? mesh_src->medge : MEM_dupallocN(mesh_src->medge), totedge); } if (!CustomData_has_layer(&tmp.pdata, CD_MPOLY)) { /* TODO(Sybren): assignment to tmp.mxxx is probably not necessary due to the * BKE_mesh_update_customdata_pointers() call below. */ tmp.mloop = (alloctype == CD_ASSIGN) ? mesh_src->mloop : MEM_dupallocN(mesh_src->mloop); tmp.mpoly = (alloctype == CD_ASSIGN) ? mesh_src->mpoly : MEM_dupallocN(mesh_src->mpoly); CustomData_add_layer(&tmp.ldata, CD_MLOOP, CD_ASSIGN, tmp.mloop, tmp.totloop); CustomData_add_layer(&tmp.pdata, CD_MPOLY, CD_ASSIGN, tmp.mpoly, tmp.totpoly); } /* object had got displacement layer, should copy this layer to save sculpted data */ /* NOTE: maybe some other layers should be copied? nazgul */ if (CustomData_has_layer(&mesh_dst->ldata, CD_MDISPS)) { if (totloop == mesh_dst->totloop) { MDisps *mdisps = CustomData_get_layer(&mesh_dst->ldata, CD_MDISPS); CustomData_add_layer(&tmp.ldata, CD_MDISPS, alloctype, mdisps, totloop); } } /* yes, must be before _and_ after tessellate */ BKE_mesh_update_customdata_pointers(&tmp, false); /* since 2.65 caller must do! */ // BKE_mesh_tessface_calc(&tmp); CustomData_free(&mesh_dst->vdata, mesh_dst->totvert); CustomData_free(&mesh_dst->edata, mesh_dst->totedge); CustomData_free(&mesh_dst->fdata, mesh_dst->totface); CustomData_free(&mesh_dst->ldata, mesh_dst->totloop); CustomData_free(&mesh_dst->pdata, mesh_dst->totpoly); /* ok, this should now use new CD shapekey data, * which should be fed through the modifier * stack */ if (tmp.totvert != mesh_dst->totvert && !did_shapekeys && mesh_dst->key) { CLOG_ERROR(&LOG, "YEEK! this should be recoded! Shape key loss!: ID '%s'", tmp.id.name); if (tmp.key && !(tmp.id.tag & LIB_TAG_NO_MAIN)) { id_us_min(&tmp.key->id); } tmp.key = NULL; } /* Clear selection history */ MEM_SAFE_FREE(tmp.mselect); tmp.totselect = 0; BLI_assert(ELEM(tmp.bb, NULL, mesh_dst->bb)); if (mesh_dst->bb) { MEM_freeN(mesh_dst->bb); tmp.bb = NULL; } /* skip the listbase */ MEMCPY_STRUCT_AFTER(mesh_dst, &tmp, id.prev); if (take_ownership) { if (alloctype == CD_ASSIGN) { CustomData_free_typemask(&mesh_src->vdata, mesh_src->totvert, ~mask->vmask); CustomData_free_typemask(&mesh_src->edata, mesh_src->totedge, ~mask->emask); CustomData_free_typemask(&mesh_src->ldata, mesh_src->totloop, ~mask->lmask); CustomData_free_typemask(&mesh_src->pdata, mesh_src->totpoly, ~mask->pmask); } BKE_id_free(NULL, mesh_src); } }