/* turns Mesh into editmesh */ void make_editMesh(Scene *scene, Object *ob) { Mesh *me= ob->data; MFace *mface; MVert *mvert; MSelect *mselect; KeyBlock *actkey; EditMesh *em; EditVert *eve, **evlist, *eve1, *eve2, *eve3, *eve4; EditFace *efa, *efa_last_sel= NULL; EditEdge *eed; EditSelection *ese; float *co, (*keyco)[3]= NULL; int tot, a, eekadoodle= 0; const short is_paint_face_sel= paint_facesel_test(ob); const short is_paint_vert_sel= is_paint_face_sel ? FALSE : paint_vertsel_test(ob); if(me->edit_mesh==NULL) me->edit_mesh= MEM_callocN(sizeof(EditMesh), "editmesh"); else /* because of reload */ free_editMesh(me->edit_mesh); em= me->edit_mesh; em->selectmode= scene->toolsettings->selectmode; // warning needs to be synced em->act_face = NULL; em->totvert= tot= me->totvert; em->totedge= me->totedge; em->totface= me->totface; if(tot==0) { return; } if(ob->actcol > 0) em->mat_nr= ob->actcol-1; /* initialize fastmalloc for editmesh */ init_editmesh_fastmalloc(em, me->totvert, me->totedge, me->totface); actkey = ob_get_keyblock(ob); if(actkey) { /* undo-ing in past for previous editmode sessions gives corrupt 'keyindex' values */ undo_editmode_clear(); keyco= actkey->data; em->shapenr= ob->shapenr; } /* make editverts */ CustomData_copy(&me->vdata, &em->vdata, CD_MASK_EDITMESH, CD_CALLOC, 0); mvert= me->mvert; evlist= (EditVert **)MEM_mallocN(tot*sizeof(void *),"evlist"); for(a=0; a<tot; a++, mvert++) { co= mvert->co; /* edit the shape key coordinate if available */ if(keyco && a < actkey->totelem) co= keyco[a]; eve= addvertlist(em, co, NULL); evlist[a]= eve; /* face select sets selection in next loop */ if(!is_paint_face_sel) eve->f |= (mvert->flag & SELECT); if (mvert->flag & ME_HIDE) eve->h= 1; normal_short_to_float_v3(eve->no, mvert->no); eve->bweight= ((float)mvert->bweight)/255.0f; /* lets overwrite the keyindex of the editvert * with the order it used to be in before * editmode */ eve->keyindex = a; CustomData_to_em_block(&me->vdata, &em->vdata, a, &eve->data); } if(actkey && actkey->totelem!=me->totvert); else { MEdge *medge= me->medge; CustomData_copy(&me->edata, &em->edata, CD_MASK_EDITMESH, CD_CALLOC, 0); /* make edges */ for(a=0; a<me->totedge; a++, medge++) { eed= addedgelist(em, evlist[medge->v1], evlist[medge->v2], NULL); /* eed can be zero when v1 and v2 are identical, dxf import does this... */ if(eed) { int is_sel; if (is_paint_vert_sel) { /* when from vertex select, flush flags to edges, * allow selection, code below handles editmode selection conversion */ is_sel= (eed->v1->f & SELECT) && (eed->v2->f & SELECT); } else { is_sel= (medge->flag & SELECT); } eed->crease= ((float)medge->crease)/255.0f; eed->bweight= ((float)medge->bweight)/255.0f; if(medge->flag & ME_SEAM) eed->seam= 1; if(medge->flag & ME_SHARP) eed->sharp = 1; if(medge->flag & ME_FGON) eed->h= EM_FGON; // 2 different defines! if(medge->flag & ME_HIDE) eed->h |= 1; if(is_sel) eed->f |= SELECT; if(em->selectmode==SCE_SELECT_EDGE) EM_select_edge(eed, eed->f & SELECT); // force edge selection to vertices, seems to be needed ... CustomData_to_em_block(&me->edata,&em->edata, a, &eed->data); } } CustomData_copy(&me->fdata, &em->fdata, CD_MASK_EDITMESH, CD_CALLOC, 0); /* make faces */ mface= me->mface; for(a=0; a<me->totface; a++, mface++) { eve1= evlist[mface->v1]; eve2= evlist[mface->v2]; if(!mface->v3) eekadoodle= 1; eve3= evlist[mface->v3]; if(mface->v4) eve4= evlist[mface->v4]; else eve4= NULL; efa= addfacelist(em, eve1, eve2, eve3, eve4, NULL, NULL); if(efa) { CustomData_to_em_block(&me->fdata, &em->fdata, a, &efa->data); efa->mat_nr= mface->mat_nr; efa->flag= mface->flag & ~ME_HIDE; /* select and hide face flag */ if(mface->flag & ME_HIDE) { efa->h= 1; } else { int is_sel; if (!is_paint_vert_sel) { is_sel= (mface->flag & ME_FACE_SEL); } else { /* when from vertex select, flush flags to edges, * allow selection, code below handles editmode selection conversion */ is_sel= ( (efa->v1->f & SELECT) && (efa->v2->f & SELECT) && (efa->v3->f & SELECT) && (efa->v4 == NULL || efa->v4->f & SELECT) ); } if (a==me->act_face) { EM_set_actFace(em, efa); } /* dont allow hidden and selected */ if(is_sel) { efa->f |= SELECT; if(is_paint_face_sel) { EM_select_face(efa, 1); /* flush down */ } efa_last_sel= efa; } } } } } if(EM_get_actFace(em, 0)==NULL && efa_last_sel) { EM_set_actFace(em, efa_last_sel); } if(eekadoodle) error("This Mesh has old style edgecodes, please put it in the bugtracker!"); MEM_freeN(evlist); end_editmesh_fastmalloc(); // resets global function pointers if(me->mselect){ //restore editselections EM_init_index_arrays(em, 1,1,1); mselect = me->mselect; for(a=0; a<me->totselect; a++, mselect++){ /*check if recorded selection is still valid, if so copy into editmesh*/ if ( (mselect->type == EDITVERT && me->mvert[mselect->index].flag & SELECT) || (mselect->type == EDITEDGE && me->medge[mselect->index].flag & SELECT) || (mselect->type == EDITFACE && me->mface[mselect->index].flag & ME_FACE_SEL) ) { ese = MEM_callocN(sizeof(EditSelection), "Edit Selection"); ese->type = mselect->type; if(ese->type == EDITVERT) ese->data = EM_get_vert_for_index(mselect->index); else if(ese->type == EDITEDGE) ese->data = EM_get_edge_for_index(mselect->index); else if(ese->type == EDITFACE) ese->data = EM_get_face_for_index(mselect->index); BLI_addtail(&(em->selected),ese); } } EM_free_index_arrays(); } /* this creates coherent selections. also needed for older files */ EM_selectmode_set(em); /* paranoia check to enforce hide rules */ EM_hide_reset(em); /* sets helper flags which arent saved */ EM_fgon_flags(em); if (EM_get_actFace(em, 0)==NULL) { EM_set_actFace(em, em->faces.first ); /* will use the first face, this is so we alwats have an active face */ } }
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); }
Mesh *BKE_mesh_copy_ex(Main *bmain, Mesh *me) { Mesh *men; MTFace *tface; MTexPoly *txface; int a, i; const int do_tessface = ((me->totface != 0) && (me->totpoly == 0)); /* only do tessface if we have no polys */ men = BKE_libblock_copy_ex(bmain, &me->id); men->mat = MEM_dupallocN(me->mat); for (a = 0; a < men->totcol; a++) { id_us_plus((ID *)men->mat[a]); } id_us_plus((ID *)men->texcomesh); CustomData_copy(&me->vdata, &men->vdata, CD_MASK_MESH, CD_DUPLICATE, men->totvert); CustomData_copy(&me->edata, &men->edata, CD_MASK_MESH, CD_DUPLICATE, men->totedge); CustomData_copy(&me->ldata, &men->ldata, CD_MASK_MESH, CD_DUPLICATE, men->totloop); CustomData_copy(&me->pdata, &men->pdata, CD_MASK_MESH, CD_DUPLICATE, men->totpoly); if (do_tessface) { CustomData_copy(&me->fdata, &men->fdata, CD_MASK_MESH, CD_DUPLICATE, men->totface); } else { mesh_tessface_clear_intern(men, FALSE); } BKE_mesh_update_customdata_pointers(men, do_tessface); /* ensure indirect linked data becomes lib-extern */ for (i = 0; i < me->fdata.totlayer; i++) { if (me->fdata.layers[i].type == CD_MTFACE) { tface = (MTFace *)me->fdata.layers[i].data; for (a = 0; a < me->totface; a++, tface++) if (tface->tpage) id_lib_extern((ID *)tface->tpage); } } for (i = 0; i < me->pdata.totlayer; i++) { if (me->pdata.layers[i].type == CD_MTEXPOLY) { txface = (MTexPoly *)me->pdata.layers[i].data; for (a = 0; a < me->totpoly; a++, txface++) if (txface->tpage) id_lib_extern((ID *)txface->tpage); } } men->edit_btmesh = NULL; men->mselect = MEM_dupallocN(men->mselect); men->bb = MEM_dupallocN(men->bb); men->key = BKE_key_copy(me->key); if (men->key) men->key->from = (ID *)men; return men; }
// ================================================================= // 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; }
void BM_mesh_copy_init_customdata(BMesh *bm_dst, BMesh *bm_src, const BMAllocTemplate *allocsize) { if (allocsize == NULL) { allocsize = &bm_mesh_allocsize_default; } CustomData_copy(&bm_src->vdata, &bm_dst->vdata, CD_MASK_BMESH, CD_CALLOC, 0); CustomData_copy(&bm_src->edata, &bm_dst->edata, CD_MASK_BMESH, CD_CALLOC, 0); CustomData_copy(&bm_src->ldata, &bm_dst->ldata, CD_MASK_BMESH, CD_CALLOC, 0); CustomData_copy(&bm_src->pdata, &bm_dst->pdata, CD_MASK_BMESH, CD_CALLOC, 0); CustomData_bmesh_init_pool(&bm_dst->vdata, allocsize->totvert, BM_VERT); CustomData_bmesh_init_pool(&bm_dst->edata, allocsize->totedge, BM_EDGE); CustomData_bmesh_init_pool(&bm_dst->ldata, allocsize->totloop, BM_LOOP); CustomData_bmesh_init_pool(&bm_dst->pdata, allocsize->totface, BM_FACE); }
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; }
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; }
Mesh *copy_mesh(Mesh *me) { Mesh *men; MTFace *tface; int a, i; men= copy_libblock(me); men->mat= MEM_dupallocN(me->mat); for(a=0; a<men->totcol; a++) { id_us_plus((ID *)men->mat[a]); } id_us_plus((ID *)men->texcomesh); CustomData_copy(&me->vdata, &men->vdata, CD_MASK_MESH, CD_DUPLICATE, men->totvert); CustomData_copy(&me->edata, &men->edata, CD_MASK_MESH, CD_DUPLICATE, men->totedge); CustomData_copy(&me->fdata, &men->fdata, CD_MASK_MESH, CD_DUPLICATE, men->totface); mesh_update_customdata_pointers(men); /* ensure indirect linked data becomes lib-extern */ for(i=0; i<me->fdata.totlayer; i++) { if(me->fdata.layers[i].type == CD_MTFACE) { tface= (MTFace*)me->fdata.layers[i].data; for(a=0; a<me->totface; a++, tface++) if(tface->tpage) id_lib_extern((ID*)tface->tpage); } } men->mselect= NULL; men->edit_mesh= NULL; men->pv= NULL; /* looks like this is no-longer supported but NULL just incase */ men->bb= MEM_dupallocN(men->bb); men->key= copy_key(me->key); if(men->key) men->key->from= (ID *)men; return men; }
/** * \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); }
/* Adds the geometry found in dm to bm */ BME_Mesh *BME_derivedmesh_to_bmesh(DerivedMesh *dm) { BME_Mesh *bm; int allocsize[4] = {512,512,2048,512}; MVert *mvert, *mv; MEdge *medge, *me; MFace *mface, *mf; int totface,totedge,totvert,i,len, numTex, numCol; BME_Vert *v1=NULL,*v2=NULL, **vert_array; BME_Edge *e=NULL; BME_Poly *f=NULL; EdgeHash *edge_hash = BLI_edgehash_new(); bm = BME_make_mesh(allocsize); /*copy custom data layout*/ CustomData_copy(&dm->vertData, &bm->vdata, CD_MASK_BMESH, CD_CALLOC, 0); CustomData_copy(&dm->edgeData, &bm->edata, CD_MASK_BMESH, CD_CALLOC, 0); CustomData_copy(&dm->faceData, &bm->pdata, CD_MASK_BMESH, CD_CALLOC, 0); /*copy face corner data*/ CustomData_to_bmeshpoly(&dm->faceData, &bm->pdata, &bm->ldata); /*initialize memory pools*/ CustomData_bmesh_init_pool(&bm->vdata, allocsize[0]); CustomData_bmesh_init_pool(&bm->edata, allocsize[1]); CustomData_bmesh_init_pool(&bm->ldata, allocsize[2]); CustomData_bmesh_init_pool(&bm->pdata, allocsize[3]); /*needed later*/ numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY); numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL); totvert = dm->getNumVerts(dm); totedge = dm->getNumEdges(dm); totface = dm->getNumFaces(dm); mvert = dm->getVertArray(dm); medge = dm->getEdgeArray(dm); mface = dm->getFaceArray(dm); vert_array = MEM_mallocN(sizeof(*vert_array)*totvert,"BME_derivedmesh_to_bmesh BME_Vert* array"); BME_model_begin(bm); /*add verts*/ for(i=0,mv = mvert; i < totvert;i++,mv++){ v1 = BME_MV(bm,mv->co); vert_array[i] = v1; v1->flag = mv->flag; v1->bweight = mv->bweight/255.0f; CustomData_to_bmesh_block(&dm->vertData, &bm->vdata, i, &v1->data); } /*add edges*/ for(i=0,me = medge; i < totedge;i++,me++){ v1 = vert_array[me->v1]; v2 = vert_array[me->v2]; e = BME_ME(bm, v1, v2); e->crease = me->crease/255.0f; e->bweight = me->bweight/255.0f; e->flag = (unsigned char)me->flag; BLI_edgehash_insert(edge_hash,me->v1,me->v2,e); CustomData_to_bmesh_block(&dm->edgeData, &bm->edata, i, &e->data); } /*add faces.*/ for(i=0,mf = mface; i < totface;i++,mf++){ BME_Edge *edar[4]; if(mf->v4) len = 4; else len = 3; edar[0] = BLI_edgehash_lookup(edge_hash,mf->v1,mf->v2); edar[1] = BLI_edgehash_lookup(edge_hash,mf->v2,mf->v3); if(len == 4){ edar[2] = BLI_edgehash_lookup(edge_hash,mf->v3,mf->v4); edar[3] = BLI_edgehash_lookup(edge_hash,mf->v4,mf->v1); } else edar[2] = BLI_edgehash_lookup(edge_hash,mf->v3,mf->v1); /*find v1 and v2*/ v1 = vert_array[mf->v1]; v2 = vert_array[mf->v2]; f = BME_MF(bm,v1,v2,edar,len); f->mat_nr = mf->mat_nr; f->flag = mf->flag; CustomData_to_bmesh_block(&dm->faceData,&bm->pdata,i,&f->data); BME_DMcorners_to_loops(bm, &dm->faceData,i,f, numCol,numTex); } BME_model_end(bm); BLI_edgehash_free(edge_hash, NULL); MEM_freeN(vert_array); return bm; }
/* adds the geometry in the bmesh to editMesh (does not free editMesh) * if td != NULL, the transdata will be mapped to the EditVert's co */ void BME_bmesh_to_editmesh(BME_Mesh *bm, BME_TransData_Head *td, EditMesh *em) { BME_Vert *v1; BME_Edge *e; BME_Poly *f; BME_TransData *vtd; EditVert *eve1, *eve2, *eve3, *eve4, **evlist; EditEdge *eed; EditFace *efa; int totvert, len, i, numTex, numCol; if (em == NULL) return; CustomData_copy(&bm->vdata, &em->vdata, CD_MASK_BMESH, CD_CALLOC, 0); CustomData_copy(&bm->edata, &em->edata, CD_MASK_BMESH, CD_CALLOC, 0); CustomData_copy(&bm->pdata, &em->fdata, CD_MASK_BMESH, CD_CALLOC, 0); CustomData_from_bmeshpoly(&em->fdata, &bm->pdata, &bm->ldata,0); numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY); numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL); /* convert to EditMesh */ /* make editverts */ totvert = BLI_countlist(&(bm->verts)); evlist= (EditVert **)MEM_mallocN(totvert*sizeof(void *),"evlist"); for (i=0,v1=bm->verts.first;v1;v1=v1->next,i++) { v1->tflag1 = i; eve1 = NULL; //XXX addvertlist(v1->co,NULL); if (td && (vtd = BME_get_transdata(td,v1))) { vtd->loc = eve1->co; } eve1->keyindex = i; evlist[i]= eve1; eve1->f = (unsigned char)v1->flag; eve1->h = (unsigned char)v1->h; eve1->bweight = v1->bweight; CustomData_em_copy_data(&bm->vdata, &em->vdata, v1->data, &eve1->data); } /* make edges */ for (e=bm->edges.first;e;e=e->next) { if(0) { //XXX if(!(findedgelist(evlist[e->v1->tflag1], evlist[e->v2->tflag1]))){ eed= NULL; //XXX addedgelist(evlist[e->v1->tflag1], evlist[e->v2->tflag1], NULL); eed->crease = e->crease; eed->bweight = e->bweight; if(e->flag & ME_SEAM) eed->seam = 1; if(e->flag & ME_SHARP) eed->sharp = 1; if(e->flag & SELECT) eed->f |= SELECT; //XXX if(e->flag & ME_FGON) eed->h= EM_FGON; // 2 different defines! if(e->flag & ME_HIDE) eed->h |= 1; if(em->selectmode==SCE_SELECT_EDGE) { ; //XXX EM_select_edge(eed, eed->f & SELECT); } CustomData_em_copy_data(&bm->edata, &em->edata, e->data, &eed->data); } } /* make faces */ for (f=bm->polys.first;f;f=f->next) { len = BME_cycle_length(f->loopbase); if (len==3 || len==4) { eve1= evlist[f->loopbase->v->tflag1]; eve2= evlist[f->loopbase->next->v->tflag1]; eve3= evlist[f->loopbase->next->next->v->tflag1]; if (len == 4) { eve4= evlist[f->loopbase->prev->v->tflag1]; } else { eve4= NULL; } efa = NULL; //XXX addfacelist(eve1, eve2, eve3, eve4, NULL, NULL); efa->mat_nr = (unsigned char)f->mat_nr; efa->flag= f->flag & ~ME_HIDE; if(f->flag & ME_FACE_SEL) { efa->f |= SELECT; } if(f->flag & ME_HIDE) efa->h= 1; // XXX flag depricated // if((G.f & G_FACESELECT) && (efa->f & SELECT)) //XXX EM_select_face(efa, 1); /* flush down */ CustomData_em_copy_data(&bm->pdata, &em->fdata, f->data, &efa->data); BME_loops_to_corners(bm, &em->fdata, efa->data, f,numCol,numTex); } } MEM_freeN(evlist); }
/* return 1: success */ static int mesh_separate_selected(wmOperator *op, Main *bmain, Scene *scene, Base *editbase) { EditMesh *em, *emnew; EditVert *eve, *v1; EditEdge *eed, *e1; EditFace *efa, *f1; Object *obedit; Mesh *me, *menew; Base *basenew; if(editbase==NULL) return 0; obedit= editbase->object; me= obedit->data; em= BKE_mesh_get_editmesh(me); if(me->key) { BKE_report(op->reports, RPT_WARNING, "Can't separate mesh with shape keys"); BKE_mesh_end_editmesh(me, em); return 0; } if(em->selected.first) BLI_freelistN(&(em->selected)); /* clear the selection order */ EM_selectmode_set(em); // enforce full consistent selection flags EM_stats_update(em); if(em->totvertsel==0) { BKE_mesh_end_editmesh(me, em); return 0; } /* we are going to work as follows: * 1. add a linked duplicate object: this will be the new one, we remember old pointer * 2. give new object empty mesh and put in editmode * 3: do a split if needed on current editmesh. * 4. copy over: all NOT selected verts, edges, faces * 5. call load_editMesh() on the new object */ /* 1 */ basenew= ED_object_add_duplicate(bmain, scene, editbase, 0); /* 0 = fully linked */ ED_base_object_select(basenew, BA_DESELECT); /* 2 */ basenew->object->data= menew= add_mesh(me->id.name+2); /* empty */ assign_matarar(basenew->object, give_matarar(obedit), *give_totcolp(obedit)); /* new in 2.5 */ me->id.us--; make_editMesh(scene, basenew->object); emnew= menew->edit_mesh; CustomData_copy(&em->vdata, &emnew->vdata, CD_MASK_EDITMESH, CD_DEFAULT, 0); CustomData_copy(&em->edata, &emnew->edata, CD_MASK_EDITMESH, CD_DEFAULT, 0); CustomData_copy(&em->fdata, &emnew->fdata, CD_MASK_EDITMESH, CD_DEFAULT, 0); /* 3 */ /* SPLIT: first make duplicate */ adduplicateflag(em, SELECT); /* SPLIT: old faces have 3x flag 128 set, delete these ones */ delfaceflag(em, 128); /* since we do tricky things with verts/edges/faces, this makes sure all is selected coherent */ EM_selectmode_set(em); /* 4 */ /* move over: everything that is selected */ for(eve= em->verts.first; eve; eve= v1) { v1= eve->next; if(eve->f & SELECT) { BLI_remlink(&em->verts, eve); BLI_addtail(&emnew->verts, eve); } } for(eed= em->edges.first; eed; eed= e1) { e1= eed->next; if(eed->f & SELECT) { BLI_remlink(&em->edges, eed); BLI_addtail(&emnew->edges, eed); } } for(efa= em->faces.first; efa; efa= f1) { f1= efa->next; if (efa == em->act_face && (efa->f & SELECT)) { EM_set_actFace(em, NULL); } if(efa->f & SELECT) { BLI_remlink(&em->faces, efa); BLI_addtail(&emnew->faces, efa); } } /* 5 */ load_editMesh(scene, basenew->object); free_editMesh(emnew); MEM_freeN(menew->edit_mesh); menew->edit_mesh= NULL; /* copy settings */ menew->texflag= me->texflag; menew->drawflag= me->drawflag; menew->flag= me->flag; menew->editflag= me->editflag; menew->smoothresh= me->smoothresh; /* hashedges are invalid now, make new! */ editMesh_set_hash(em); DAG_id_tag_update(&obedit->id, OB_RECALC_DATA); DAG_id_tag_update(&basenew->object->id, OB_RECALC_DATA); BKE_mesh_end_editmesh(me, em); return 1; }
/* 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); }
static void *editMesh_to_undoMesh(void *emv) { EditMesh *em= (EditMesh *)emv; UndoMesh *um; EditVert *eve; EditEdge *eed; EditFace *efa; EditSelection *ese; EditVertC *evec=NULL; EditEdgeC *eedc=NULL; EditFaceC *efac=NULL; EditSelectionC *esec=NULL; int a; um= MEM_callocN(sizeof(UndoMesh), "undomesh"); um->selectmode = em->selectmode; um->shapenr = em->shapenr; for(eve=em->verts.first; eve; eve= eve->next) um->totvert++; for(eed=em->edges.first; eed; eed= eed->next) um->totedge++; for(efa=em->faces.first; efa; efa= efa->next) um->totface++; for(ese=em->selected.first; ese; ese=ese->next) um->totsel++; /* malloc blocks */ if(um->totvert) evec= um->verts= MEM_callocN(um->totvert*sizeof(EditVertC), "allvertsC"); if(um->totedge) eedc= um->edges= MEM_callocN(um->totedge*sizeof(EditEdgeC), "alledgesC"); if(um->totface) efac= um->faces= MEM_callocN(um->totface*sizeof(EditFaceC), "allfacesC"); if(um->totsel) esec= um->selected= MEM_callocN(um->totsel*sizeof(EditSelectionC), "allselections"); if(um->totvert) CustomData_copy(&em->vdata, &um->vdata, CD_MASK_EDITMESH, CD_CALLOC, um->totvert); if(um->totedge) CustomData_copy(&em->edata, &um->edata, CD_MASK_EDITMESH, CD_CALLOC, um->totedge); if(um->totface) CustomData_copy(&em->fdata, &um->fdata, CD_MASK_EDITMESH, CD_CALLOC, um->totface); /* now copy vertices */ a = 0; for(eve=em->verts.first; eve; eve= eve->next, evec++, a++) { copy_v3_v3(evec->co, eve->co); copy_v3_v3(evec->no, eve->no); evec->f= eve->f; evec->h= eve->h; evec->keyindex= eve->keyindex; eve->tmp.l = a; /*store index*/ evec->bweight= (short)(eve->bweight*255.0f); CustomData_from_em_block(&em->vdata, &um->vdata, eve->data, a); } /* copy edges */ a = 0; for(eed=em->edges.first; eed; eed= eed->next, eedc++, a++) { eedc->v1= (int)eed->v1->tmp.l; eedc->v2= (int)eed->v2->tmp.l; eedc->f= eed->f; eedc->h= eed->h; eedc->seam= eed->seam; eedc->sharp= eed->sharp; eedc->crease= (short)(eed->crease*255.0f); eedc->bweight= (short)(eed->bweight*255.0f); eedc->fgoni= eed->fgoni; eed->tmp.l = a; /*store index*/ CustomData_from_em_block(&em->edata, &um->edata, eed->data, a); } /* copy faces */ a = 0; for(efa=em->faces.first; efa; efa= efa->next, efac++, a++) { efac->v1= (int)efa->v1->tmp.l; efac->v2= (int)efa->v2->tmp.l; efac->v3= (int)efa->v3->tmp.l; if(efa->v4) efac->v4= (int)efa->v4->tmp.l; else efac->v4= -1; efac->mat_nr= efa->mat_nr; efac->flag= efa->flag; efac->f= efa->f; efac->h= efa->h; efac->fgonf= efa->fgonf; efa->tmp.l = a; /*store index*/ CustomData_from_em_block(&em->fdata, &um->fdata, efa->data, a); } a = 0; for(ese=em->selected.first; ese; ese=ese->next, esec++){ esec->type = ese->type; if(ese->type == EDITVERT) a = esec->index = ((EditVert*)ese->data)->tmp.l; else if(ese->type == EDITEDGE) a = esec->index = ((EditEdge*)ese->data)->tmp.l; else if(ese->type == EDITFACE) a = esec->index = ((EditFace*)ese->data)->tmp.l; } return um; }
/** * \brief Mesh -> BMesh * \param bm: The mesh to write into, while this is typically a newly created BMesh, * merging into existing data is supported. * Note the custom-data layout isn't used. * If more comprehensive merging is needed we should move this into a separate function * since this should be kept fast for edit-mode switching and storing undo steps. * * \warning This function doesn't calculate face normals. */ void BM_mesh_bm_from_me( BMesh *bm, Mesh *me, const struct BMeshFromMeshParams *params) { const bool is_new = !(bm->totvert || (bm->vdata.totlayer || bm->edata.totlayer || bm->pdata.totlayer || bm->ldata.totlayer)); MVert *mvert; MEdge *medge; MLoop *mloop; MPoly *mp; KeyBlock *actkey, *block; BMVert *v, **vtable = NULL; BMEdge *e, **etable = NULL; BMFace *f, **ftable = NULL; float (*keyco)[3] = NULL; int totuv, totloops, i; if (!me || !me->totvert) { if (me && is_new) { /*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 */ } if (is_new) { 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); } } /* -------------------------------------------------------------------- */ /* Shape Key */ int tot_shape_keys = me->key ? BLI_listbase_count(&me->key->block) : 0; if (is_new == false) { tot_shape_keys = min_ii(tot_shape_keys, CustomData_number_of_layers(&bm->vdata, CD_SHAPEKEY)); } const float (**shape_key_table)[3] = tot_shape_keys ? BLI_array_alloca(shape_key_table, tot_shape_keys) : NULL; if ((params->active_shapekey != 0) && (me->key != NULL)) { actkey = BLI_findlink(&me->key->block, params->active_shapekey - 1); } else { actkey = NULL; } if (is_new) { if (tot_shape_keys || params->add_key_index) { CustomData_add_layer(&bm->vdata, CD_SHAPE_KEYINDEX, CD_ASSIGN, NULL, 0); } } if (tot_shape_keys) { if (is_new) { /* 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 = params->use_shapekey ? actkey->data : NULL; if (is_new) { bm->shapenr = params->active_shapekey; } } for (i = 0, block = me->key->block.first; i < tot_shape_keys; block = block->next, i++) { if (is_new) { CustomData_add_layer_named(&bm->vdata, CD_SHAPEKEY, CD_ASSIGN, NULL, 0, block->name); int j = CustomData_get_layer_index_n(&bm->vdata, CD_SHAPEKEY, i); bm->vdata.layers[j].uid = block->uid; } shape_key_table[i] = (const float (*)[3])block->data; } } if (is_new) { 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); } const int cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT); const int cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT); const int cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE); const int cd_shape_key_offset = me->key ? CustomData_get_offset(&bm->vdata, CD_SHAPEKEY) : -1; const int cd_shape_keyindex_offset = is_new && (tot_shape_keys || params->add_key_index) ? CustomData_get_offset(&bm->vdata, CD_SHAPE_KEYINDEX) : -1; vtable = MEM_mallocN(sizeof(BMVert **) * me->totvert, __func__); for (i = 0, mvert = me->mvert; i < me->totvert; i++, mvert++) { v = vtable[i] = BM_vert_create(bm, keyco ? 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 shape key original index */ if (cd_shape_keyindex_offset != -1) BM_ELEM_CD_SET_INT(v, cd_shape_keyindex_offset, i); /* set shapekey data */ if (tot_shape_keys) { float (*co_dst)[3] = BM_ELEM_CD_GET_VOID_P(v, cd_shape_key_offset); for (int j = 0; j < tot_shape_keys; j++, co_dst++) { copy_v3_v3(*co_dst, shape_key_table[j][i]); } } } if (is_new) { bm->elem_index_dirty &= ~BM_VERT; /* added in order, clear dirty flag */ } etable = MEM_mallocN(sizeof(BMEdge **) * me->totedge, __func__); 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); } if (is_new) { bm->elem_index_dirty &= ~BM_EDGE; /* added in order, clear dirty flag */ } /* only needed for selection. */ if (me->mselect && me->totselect != 0) { ftable = MEM_mallocN(sizeof(BMFace **) * me->totpoly, __func__); } mloop = me->mloop; mp = me->mpoly; for (i = 0, totloops = 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 (ftable != NULL) { ftable[i] = f; } 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; int j = mp->loopstart; l_iter = l_first = BM_FACE_FIRST_LOOP(f); do { /* don't use 'j' since we may have skipped some faces, hence some loops. */ BM_elem_index_set(l_iter, totloops++); /* set_ok */ /* 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 (params->calc_face_normal) { BM_face_normal_update(f); } } if (is_new) { bm->elem_index_dirty &= ~(BM_FACE | BM_LOOP); /* added in order, clear dirty flag */ } /* -------------------------------------------------------------------- */ /* MSelect clears the array elements (avoid adding multiple times). * * Take care to keep this last and not use (v/e/ftable) after this. */ if (me->mselect && me->totselect != 0) { MSelect *msel; for (i = 0, msel = me->mselect; i < me->totselect; i++, msel++) { BMElem **ele_p; switch (msel->type) { case ME_VSEL: ele_p = (BMElem **)&vtable[msel->index]; break; case ME_ESEL: ele_p = (BMElem **)&etable[msel->index]; break; case ME_FSEL: ele_p = (BMElem **)&ftable[msel->index]; break; default: continue; } if (*ele_p != NULL) { BM_select_history_store_notest(bm, *ele_p); *ele_p = NULL; } } } else { BM_select_history_clear(bm); } MEM_freeN(vtable); MEM_freeN(etable); if (ftable) { MEM_freeN(ftable); } }
/*move the EditMesh conversion functions to editmesh_tools.c*/ BME_Mesh *BME_editmesh_to_bmesh(EditMesh *em) { BME_Mesh *bm; int allocsize[4] = {512,512,2048,512}, numTex, numCol; BME_Vert *v1, *v2; BME_Edge *e, *edar[4]; BME_Poly *f; EditVert *eve; EditEdge *eed; EditFace *efa; int len; bm = BME_make_mesh(allocsize); /*copy custom data layout*/ CustomData_copy(&em->vdata, &bm->vdata, CD_MASK_BMESH, CD_CALLOC, 0); CustomData_copy(&em->edata, &bm->edata, CD_MASK_BMESH, CD_CALLOC, 0); CustomData_copy(&em->fdata, &bm->pdata, CD_MASK_BMESH, CD_CALLOC, 0); /*copy face corner data*/ CustomData_to_bmeshpoly(&em->fdata, &bm->pdata, &bm->ldata); /*initialize memory pools*/ CustomData_bmesh_init_pool(&bm->vdata, allocsize[0]); CustomData_bmesh_init_pool(&bm->edata, allocsize[1]); CustomData_bmesh_init_pool(&bm->ldata, allocsize[2]); CustomData_bmesh_init_pool(&bm->pdata, allocsize[3]); /*needed later*/ numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY); numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL); BME_model_begin(bm); /*add verts*/ eve= em->verts.first; while(eve) { v1 = BME_MV(bm,eve->co); VECCOPY(v1->no,eve->no); v1->flag = eve->f; v1->h = eve->h; v1->bweight = eve->bweight; /*Copy Custom Data*/ CustomData_bmesh_copy_data(&em->vdata, &bm->vdata, eve->data, &v1->data); eve->tmp.v = (EditVert*)v1; eve = eve->next; } /*add edges*/ eed= em->edges.first; while(eed) { v1 = (BME_Vert*)eed->v1->tmp.v; v2 = (BME_Vert*)eed->v2->tmp.v; e = BME_ME(bm, v1, v2); e->crease = eed->crease; e->bweight = eed->bweight; e->flag = eed->f & SELECT; if(eed->sharp) e->flag |= ME_SHARP; if(eed->seam) e->flag |= ME_SEAM; //XXX if(eed->h & EM_FGON) e->flag |= ME_FGON; if(eed->h & 1) e->flag |= ME_HIDE; eed->tmp.e = (EditEdge*)e; CustomData_bmesh_copy_data(&em->edata, &bm->edata, eed->data, &e->data); eed = eed->next; } /*add faces.*/ efa= em->faces.first; while(efa) { if(efa->v4) len = 4; else len = 3; edar[0] = (BME_Edge*)efa->e1->tmp.e; edar[1] = (BME_Edge*)efa->e2->tmp.e; edar[2] = (BME_Edge*)efa->e3->tmp.e; if(len == 4){ edar[3] = (BME_Edge*)efa->e4->tmp.e; } /*find v1 and v2*/ v1 = (BME_Vert*)efa->v1->tmp.v; v2 = (BME_Vert*)efa->v2->tmp.v; f = BME_MF(bm,v1,v2,edar,len); f->mat_nr = efa->mat_nr; f->flag = efa->flag; if(efa->h) { f->flag |= ME_HIDE; f->flag &= ~ME_FACE_SEL; } else { if(efa->f & 1) f->flag |= ME_FACE_SEL; else f->flag &= ~ME_FACE_SEL; } CustomData_bmesh_copy_data(&em->fdata, &bm->pdata, efa->data, &f->data); BME_corners_to_loops(bm, &em->fdata, efa->data, f,numCol,numTex); efa = efa->next; } BME_model_end(bm); return bm; }
/* 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); } }