/** * \return if succeeded. */ bool ED_workspace_delete(WorkSpace *workspace, Main *bmain, bContext *C, wmWindowManager *wm) { if (BLI_listbase_is_single(&bmain->workspaces)) { return false; } ListBase ordered; BKE_id_ordered_list(&ordered, &bmain->workspaces); WorkSpace *prev = NULL, *next = NULL; for (LinkData *link = ordered.first; link; link = link->next) { if (link->data == workspace) { prev = link->prev ? link->prev->data : NULL; next = link->next ? link->next->data : NULL; break; } } BLI_freelistN(&ordered); BLI_assert((prev != NULL) || (next != NULL)); for (wmWindow *win = wm->windows.first; win; win = win->next) { WorkSpace *workspace_active = WM_window_get_active_workspace(win); if (workspace_active == workspace) { ED_workspace_change((prev != NULL) ? prev : next, C, wm, win); } } BKE_id_free(bmain, &workspace->id); return true; }
Mesh *BKE_mesh_create_derived_for_modifier(struct Depsgraph *depsgraph, Scene *scene, Object *ob_eval, ModifierData *md_eval, int build_shapekey_layers) { Mesh *me = ob_eval->runtime.mesh_orig ? ob_eval->runtime.mesh_orig : ob_eval->data; const ModifierTypeInfo *mti = modifierType_getInfo(md_eval->type); Mesh *result; KeyBlock *kb; ModifierEvalContext mectx = {depsgraph, ob_eval, 0}; if (!(md_eval->mode & eModifierMode_Realtime)) { return NULL; } if (mti->isDisabled && mti->isDisabled(scene, md_eval, 0)) { return NULL; } if (build_shapekey_layers && me->key && (kb = BLI_findlink(&me->key->block, ob_eval->shapenr - 1))) { BKE_keyblock_convert_to_mesh(kb, me); } if (mti->type == eModifierTypeType_OnlyDeform) { int numVerts; float(*deformedVerts)[3] = BKE_mesh_vertexCos_get(me, &numVerts); BKE_id_copy_ex(NULL, &me->id, (ID **)&result, LIB_ID_COPY_LOCALIZE); mti->deformVerts(md_eval, &mectx, result, deformedVerts, numVerts); BKE_mesh_apply_vert_coords(result, deformedVerts); if (build_shapekey_layers) { add_shapekey_layers(result, me); } MEM_freeN(deformedVerts); } else { Mesh *mesh_temp; BKE_id_copy_ex(NULL, &me->id, (ID **)&mesh_temp, LIB_ID_COPY_LOCALIZE); if (build_shapekey_layers) { add_shapekey_layers(mesh_temp, me); } result = mti->applyModifier(md_eval, &mectx, mesh_temp); ASSERT_IS_VALID_MESH(result); if (mesh_temp != result) { BKE_id_free(NULL, mesh_temp); } } return result; }
static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) { ExplodeModifierData *emd = (ExplodeModifierData *)md; ParticleSystemModifierData *psmd = findPrecedingParticlesystem(ctx->object, md); if (psmd) { ParticleSystem *psys = psmd->psys; if (psys == NULL || psys->totpart == 0) { return mesh; } if (psys->part == NULL || psys->particles == NULL) { return mesh; } if (psmd->mesh_final == NULL) { return mesh; } BKE_mesh_tessface_ensure(mesh); /* BMESH - UNTIL MODIFIER IS UPDATED FOR MPoly */ /* 1. find faces to be exploded if needed */ if (emd->facepa == NULL || psmd->flag & eParticleSystemFlag_Pars || emd->flag & eExplodeFlag_CalcFaces || MEM_allocN_len(emd->facepa) / sizeof(int) != mesh->totface) { if (psmd->flag & eParticleSystemFlag_Pars) { psmd->flag &= ~eParticleSystemFlag_Pars; } if (emd->flag & eExplodeFlag_CalcFaces) { emd->flag &= ~eExplodeFlag_CalcFaces; } createFacepa(emd, psmd, mesh); } /* 2. create new mesh */ Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); if (emd->flag & eExplodeFlag_EdgeCut) { int *facepa = emd->facepa; Mesh *split_m = cutEdges(emd, mesh); Mesh *explode = explodeMesh(emd, psmd, ctx, scene, split_m); MEM_freeN(emd->facepa); emd->facepa = facepa; BKE_id_free(NULL, split_m); return explode; } else { return explodeMesh(emd, psmd, ctx, scene, mesh); } } return mesh; }
static void deformVerts(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh, float (*vertexCos)[3], int numVerts) { Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false); correctivesmooth_modifier_do( md, ctx->depsgraph, ctx->object, mesh_src, vertexCos, (unsigned int)numVerts, NULL); if (mesh_src != mesh) { BKE_id_free(NULL, mesh_src); } }
static void deformVerts(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh, float (*vertexCos)[3], int numVerts) { WarpModifierData *wmd = (WarpModifierData *)md; Mesh *mesh_src = NULL; if (wmd->defgrp_name[0] != '\0' || wmd->texture != NULL) { /* mesh_src is only needed for vgroups and textures. */ mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false); } warpModifier_do(wmd, ctx, mesh_src, vertexCos, numVerts); if (!ELEM(mesh_src, NULL, mesh)) { BKE_id_free(NULL, mesh_src); } }
/* settings: 1 - preview, 2 - render * * The convention goes as following: * * - Passing original object with apply_modifiers=false will give a * non-modified non-deformed mesh. * The result mesh will point to datablocks from the original "domain". For * example, materials will be original. * * - Passing original object with apply_modifiers=true will give a mesh which * has all modifiers applied. * The result mesh will point to datablocks from the original "domain". For * example, materials will be original. * * - Passing evaluated object will ignore apply_modifiers argument, and the * result always contains all modifiers applied. * The result mesh will point to an evaluated datablocks. For example, * materials will be an evaluated IDs from the dependency graph. */ Mesh *BKE_mesh_new_from_object(Depsgraph *depsgraph, Main *bmain, Scene *sce, Object *ob, const bool apply_modifiers, const bool calc_undeformed) { Mesh *tmpmesh; Curve *tmpcu = NULL, *copycu; int i; const bool render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER); bool effective_apply_modifiers = apply_modifiers; bool do_mat_id_data_us = true; Object *object_input = ob; Object *object_eval = DEG_get_evaluated_object(depsgraph, object_input); Object object_for_eval; if (object_eval == object_input) { /* Evaluated mesh contains all modifiers applied already. * The other types of object has them applied, but are stored in other * data structures than a mesh. So need to apply modifiers again on a * temporary copy before converting result to mesh. */ if (object_input->type == OB_MESH) { effective_apply_modifiers = false; } else { effective_apply_modifiers = true; } object_for_eval = *object_eval; } else { if (apply_modifiers) { object_for_eval = *object_eval; if (object_for_eval.runtime.mesh_orig != NULL) { object_for_eval.data = object_for_eval.runtime.mesh_orig; } } else { object_for_eval = *object_input; } } const bool cage = !effective_apply_modifiers; /* perform the mesh extraction based on type */ switch (object_for_eval.type) { case OB_FONT: case OB_CURVE: case OB_SURF: { ListBase dispbase = {NULL, NULL}; Mesh *me_eval_final = NULL; int uv_from_orco; /* copies object and modifiers (but not the data) */ Object *tmpobj; BKE_id_copy_ex(NULL, &object_for_eval.id, (ID **)&tmpobj, LIB_ID_COPY_LOCALIZE); tmpcu = (Curve *)tmpobj->data; /* Copy cached display list, it might be needed by the stack evaluation. * Ideally stack should be able to use render-time display list, but doing * so is quite tricky and not safe so close to the release. * * TODO(sergey): Look into more proper solution. */ if (object_for_eval.runtime.curve_cache != NULL) { if (tmpobj->runtime.curve_cache == NULL) { tmpobj->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for curve types"); } BKE_displist_copy(&tmpobj->runtime.curve_cache->disp, &object_for_eval.runtime.curve_cache->disp); } /* if getting the original caged mesh, delete object modifiers */ if (cage) { BKE_object_free_modifiers(tmpobj, LIB_ID_CREATE_NO_USER_REFCOUNT); } /* copies the data, but *not* the shapekeys. */ BKE_id_copy_ex(NULL, object_for_eval.data, (ID **)©cu, LIB_ID_COPY_LOCALIZE); tmpobj->data = copycu; /* make sure texture space is calculated for a copy of curve, * it will be used for the final result. */ BKE_curve_texspace_calc(copycu); /* temporarily set edit so we get updates from edit mode, but * also because for text datablocks copying it while in edit * mode gives invalid data structures */ copycu->editfont = tmpcu->editfont; copycu->editnurb = tmpcu->editnurb; /* get updated display list, and convert to a mesh */ BKE_displist_make_curveTypes_forRender( depsgraph, sce, tmpobj, &dispbase, &me_eval_final, false, NULL); copycu->editfont = NULL; copycu->editnurb = NULL; tmpobj->runtime.mesh_eval = me_eval_final; /* convert object type to mesh */ uv_from_orco = (tmpcu->flag & CU_UV_ORCO) != 0; BKE_mesh_from_nurbs_displist( bmain, tmpobj, &dispbase, uv_from_orco, tmpcu->id.name + 2, true); /* Function above also frees copycu (aka tmpobj->data), make this obvious here. */ copycu = NULL; tmpmesh = tmpobj->data; id_us_min( &tmpmesh->id); /* Gets one user from its creation in BKE_mesh_from_nurbs_displist(). */ BKE_displist_free(&dispbase); /* BKE_mesh_from_nurbs changes the type to a mesh, check it worked. * if it didn't the curve did not have any segments or otherwise * would have generated an empty mesh */ if (tmpobj->type != OB_MESH) { BKE_id_free(NULL, tmpobj); return NULL; } BKE_id_free(NULL, tmpobj); /* XXX The curve to mesh conversion is convoluted... * But essentially, BKE_mesh_from_nurbs_displist() * already transfers the ownership of materials from the temp copy of the Curve ID to the * new Mesh ID, so we do not want to increase materials' usercount later. */ do_mat_id_data_us = false; break; } case OB_MBALL: { /* metaballs don't have modifiers, so just convert to mesh */ Object *basis_ob = BKE_mball_basis_find(sce, object_input); /* todo, re-generatre for render-res */ /* metaball_polygonize(scene, ob) */ if (basis_ob != object_input) { /* Only do basis metaball. */ return NULL; } tmpmesh = BKE_mesh_add(bmain, ((ID *)object_for_eval.data)->name + 2); /* BKE_mesh_add gives us a user count we don't need */ id_us_min(&tmpmesh->id); if (render) { ListBase disp = {NULL, NULL}; BKE_displist_make_mball_forRender(depsgraph, sce, &object_for_eval, &disp); BKE_mesh_from_metaball(&disp, tmpmesh); BKE_displist_free(&disp); } else { ListBase disp = {NULL, NULL}; if (object_for_eval.runtime.curve_cache) { disp = object_for_eval.runtime.curve_cache->disp; } BKE_mesh_from_metaball(&disp, tmpmesh); } BKE_mesh_texspace_copy_from_object(tmpmesh, &object_for_eval); break; } case OB_MESH: /* copies object and modifiers (but not the data) */ if (cage) { /* copies the data (but *not* the shapekeys). */ Mesh *mesh = object_for_eval.data; BKE_id_copy_ex(bmain, &mesh->id, (ID **)&tmpmesh, 0); /* XXX BKE_mesh_copy() already handles materials usercount. */ do_mat_id_data_us = false; } /* if not getting the original caged mesh, get final derived mesh */ else { /* Make a dummy mesh, saves copying */ Mesh *me_eval; CustomData_MeshMasks mask = CD_MASK_MESH; /* this seems more suitable, exporter, * for example, needs CD_MASK_MDEFORMVERT */ if (calc_undeformed) { mask.vmask |= CD_MASK_ORCO; } if (render) { me_eval = mesh_create_eval_final_render(depsgraph, sce, &object_for_eval, &mask); } else { me_eval = mesh_create_eval_final_view(depsgraph, sce, &object_for_eval, &mask); } tmpmesh = BKE_mesh_add(bmain, ((ID *)object_for_eval.data)->name + 2); BKE_mesh_nomain_to_mesh(me_eval, tmpmesh, &object_for_eval, &mask, true); /* Copy autosmooth settings from original mesh. */ Mesh *me = (Mesh *)object_for_eval.data; tmpmesh->flag |= (me->flag & ME_AUTOSMOOTH); tmpmesh->smoothresh = me->smoothresh; } /* BKE_mesh_add/copy gives us a user count we don't need */ id_us_min(&tmpmesh->id); break; default: /* "Object does not have geometry data") */ return NULL; } /* Copy materials to new mesh */ switch (object_for_eval.type) { case OB_SURF: case OB_FONT: case OB_CURVE: tmpmesh->totcol = tmpcu->totcol; /* free old material list (if it exists) and adjust user counts */ if (tmpcu->mat) { for (i = tmpcu->totcol; i-- > 0;) { /* are we an object material or data based? */ tmpmesh->mat[i] = give_current_material(object_input, i + 1); if (((object_for_eval.matbits && object_for_eval.matbits[i]) || do_mat_id_data_us) && tmpmesh->mat[i]) { id_us_plus(&tmpmesh->mat[i]->id); } } } break; case OB_MBALL: { MetaBall *tmpmb = (MetaBall *)object_for_eval.data; tmpmesh->mat = MEM_dupallocN(tmpmb->mat); tmpmesh->totcol = tmpmb->totcol; /* free old material list (if it exists) and adjust user counts */ if (tmpmb->mat) { for (i = tmpmb->totcol; i-- > 0;) { /* are we an object material or data based? */ tmpmesh->mat[i] = give_current_material(object_input, i + 1); if (((object_for_eval.matbits && object_for_eval.matbits[i]) || do_mat_id_data_us) && tmpmesh->mat[i]) { id_us_plus(&tmpmesh->mat[i]->id); } } } break; } case OB_MESH: if (!cage) { Mesh *origmesh = object_for_eval.data; tmpmesh->flag = origmesh->flag; tmpmesh->mat = MEM_dupallocN(origmesh->mat); tmpmesh->totcol = origmesh->totcol; tmpmesh->smoothresh = origmesh->smoothresh; if (origmesh->mat) { for (i = origmesh->totcol; i-- > 0;) { /* are we an object material or data based? */ tmpmesh->mat[i] = give_current_material(object_input, i + 1); if (((object_for_eval.matbits && object_for_eval.matbits[i]) || do_mat_id_data_us) && tmpmesh->mat[i]) { id_us_plus(&tmpmesh->mat[i]->id); } } } } break; } /* end copy materials */ return tmpmesh; }
/* this may fail replacing ob->data, be sure to check ob->type */ void BKE_mesh_from_nurbs_displist(Main *bmain, Object *ob, ListBase *dispbase, const bool use_orco_uv, const char *obdata_name, bool temporary) { Object *ob1; Mesh *me_eval = ob->runtime.mesh_eval; Mesh *me; Curve *cu; MVert *allvert = NULL; MEdge *alledge = NULL; MLoop *allloop = NULL; MLoopUV *alluv = NULL; MPoly *allpoly = NULL; int totvert, totedge, totloop, totpoly; cu = ob->data; if (me_eval == NULL) { if (BKE_mesh_nurbs_displist_to_mdata(ob, dispbase, &allvert, &totvert, &alledge, &totedge, &allloop, &allpoly, (use_orco_uv) ? &alluv : NULL, &totloop, &totpoly) != 0) { /* Error initializing */ return; } /* make mesh */ me = BKE_mesh_add(bmain, obdata_name); me->totvert = totvert; me->totedge = totedge; me->totloop = totloop; me->totpoly = totpoly; me->mvert = CustomData_add_layer(&me->vdata, CD_MVERT, CD_ASSIGN, allvert, me->totvert); me->medge = CustomData_add_layer(&me->edata, CD_MEDGE, CD_ASSIGN, alledge, me->totedge); me->mloop = CustomData_add_layer(&me->ldata, CD_MLOOP, CD_ASSIGN, allloop, me->totloop); me->mpoly = CustomData_add_layer(&me->pdata, CD_MPOLY, CD_ASSIGN, allpoly, me->totpoly); if (alluv) { const char *uvname = "Orco"; me->mloopuv = CustomData_add_layer_named( &me->ldata, CD_MLOOPUV, CD_ASSIGN, alluv, me->totloop, uvname); } BKE_mesh_calc_normals(me); } else { me = BKE_mesh_add(bmain, obdata_name); ob->runtime.mesh_eval = NULL; BKE_mesh_nomain_to_mesh(me_eval, me, ob, &CD_MASK_MESH, true); } me->totcol = cu->totcol; me->mat = cu->mat; /* Copy evaluated texture space from curve to mesh. * * Note that we disable auto texture space feature since that will cause * texture space to evaluate differently for curve and mesh, since curve * uses CV to calculate bounding box, and mesh uses what is coming from * tessellated curve. */ me->texflag = cu->texflag & ~CU_AUTOSPACE; copy_v3_v3(me->loc, cu->loc); copy_v3_v3(me->size, cu->size); copy_v3_v3(me->rot, cu->rot); BKE_mesh_texspace_calc(me); cu->mat = NULL; cu->totcol = 0; /* Do not decrement ob->data usercount here, * it's done at end of func with BKE_id_free_us() call. */ ob->data = me; ob->type = OB_MESH; /* other users */ ob1 = bmain->objects.first; while (ob1) { if (ob1->data == cu) { ob1->type = OB_MESH; id_us_min((ID *)ob1->data); ob1->data = ob->data; id_us_plus((ID *)ob1->data); } ob1 = ob1->id.next; } if (temporary) { /* For temporary objects in BKE_mesh_new_from_object don't remap * the entire scene with associated depsgraph updates, which are * problematic for renderers exporting data. */ BKE_id_free(NULL, cu); } else { BKE_id_free_us(bmain, cu); } }
/* 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); } }