From 7b95d64d2f521cafe6a521af5b082c0a13cf8460 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Thu, 28 Mar 2019 11:42:53 +0100 Subject: Cleanup: better naming, comments, variable scoping in mesh_calc_modifiers. --- source/blender/blenkernel/intern/DerivedMesh.c | 825 +++++++++++++------------ 1 file changed, 416 insertions(+), 409 deletions(-) (limited to 'source/blender/blenkernel') diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index 886545ff4b1..ac2ae8a1e35 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -879,18 +879,18 @@ static Mesh *create_orco_mesh(Object *ob, Mesh *me, BMEditMesh *em, int layer) static void add_orco_mesh( Object *ob, BMEditMesh *em, Mesh *mesh, - Mesh *me_orco, int layer) + Mesh *mesh_orco, int layer) { float (*orco)[3], (*layerorco)[3]; int totvert, free; totvert = mesh->totvert; - if (me_orco) { + if (mesh_orco) { free = 1; - if (me_orco->totvert == totvert) { - orco = BKE_mesh_vertexCos_get(me_orco, NULL); + if (mesh_orco->totvert == totvert) { + orco = BKE_mesh_vertexCos_get(mesh_orco, NULL); } else { orco = BKE_mesh_vertexCos_get(mesh, NULL); @@ -991,6 +991,59 @@ static void mesh_copy_autosmooth(Mesh *me, Mesh *me_orig) } } +static void mesh_calc_modifier_final_normals( + const Mesh *mesh_input, + const CustomData_MeshMasks *dataMask, + const bool sculpt_dyntopo, + Mesh *mesh_final) +{ + /* Compute normals. */ + const bool do_loop_normals = ((mesh_input->flag & ME_AUTOSMOOTH) != 0 || + (dataMask->lmask & CD_MASK_NORMAL) != 0); + /* Some modifiers may need this info from their target (other) object, simpler to generate it here as well. + * Note that they will always be generated when no loop normals are comptuted, + * since they are needed by drawing code. */ + const bool do_poly_normals = ((dataMask->pmask & CD_MASK_NORMAL) != 0); + + if (do_loop_normals) { + /* In case we also need poly normals, add the layer here, then BKE_mesh_calc_normals_split() will fill it. */ + if (do_poly_normals) { + if (!CustomData_has_layer(&mesh_final->pdata, CD_NORMAL)) { + CustomData_add_layer(&mesh_final->pdata, CD_NORMAL, CD_CALLOC, NULL, mesh_final->totpoly); + } + } + /* Compute loop normals (note: will compute poly and vert normals as well, if needed!) */ + BKE_mesh_calc_normals_split(mesh_final); + BKE_mesh_tessface_clear(mesh_final); + } + + if (sculpt_dyntopo == false) { + /* watch this! after 2.75a we move to from tessface to looptri (by default) */ + if (dataMask->fmask & CD_MASK_MFACE) { + BKE_mesh_tessface_ensure(mesh_final); + } + + /* without this, drawing ngon tri's faces will show ugly tessellated face + * normals and will also have to calculate normals on the fly, try avoid + * this where possible since calculating polygon normals isn't fast, + * note that this isn't a problem for subsurf (only quads) or editmode + * which deals with drawing differently. + * + * Only calc vertex normals if they are flagged as dirty. + * If using loop normals, poly nors have already been computed. + */ + if (!do_loop_normals) { + BKE_mesh_ensure_normals_for_display(mesh_final); + } + } + + /* Some modifiers, like datatransfer, may generate those data as temp layer, we do not want to keep them, + * as they are used by display code when available (i.e. even if autosmooth is disabled). */ + if (!do_loop_normals && CustomData_has_layer(&mesh_final->ldata, CD_NORMAL)) { + CustomData_free_layers(&mesh_final->ldata, CD_NORMAL, mesh_final->totloop); + } +} + static void mesh_calc_modifiers( struct Depsgraph *depsgraph, Scene *scene, Object *ob, @@ -998,58 +1051,62 @@ static void mesh_calc_modifiers( const bool need_mapping, const CustomData_MeshMasks *dataMask, const int index, - const bool useCache, + const bool use_cache, /* return args */ Mesh **r_deform, Mesh **r_final) { - ModifierData *firstmd, *md, *previewmd = NULL; - CDMaskLink *datamasks, *curr; - /* XXX Always copying POLYINDEX, else tessellated data are no more valid! */ - CustomData_MeshMasks mask, nextmask, previewmask = {0}, append_mask = CD_MASK_BAREMESH_ORIGINDEX; - - float (*deformedVerts)[3] = NULL; - int numVerts = ((Mesh *)ob->data)->totvert; - const bool useRenderParams = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER); - const int required_mode = useRenderParams ? eModifierMode_Render : eModifierMode_Realtime; + /* Input and final mesh. Final mesh is only created the moment the first + * constructive modifier is executed, or a deform modifier needs normals + * or certain data layers. */ + Mesh *mesh_input = ob->data; + Mesh *mesh_final = NULL; + Mesh *mesh_deform = NULL; + BLI_assert((mesh_input->id.tag & LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT) == 0); + + /* Deformed vertex locations array. Deform only modifier need this type of + * float array rather than MVert*. Tracked along with mesh_final as an + * optimization to avoid copying coordinates back and forth if there are + * multiple sequential deform only modifiers. */ + float (*deformed_verts)[3] = NULL; + int num_deformed_verts = mesh_input->totvert; bool isPrevDeform = false; + + /* Mesh with constructive modifiers but no deformation applied. Tracked + * along with final mesh if undeformed / orco coordinates are requested + * for texturing. */ + Mesh *mesh_orco = NULL; + Mesh *mesh_orco_cloth = NULL; + + /* Modifier evaluation modes. */ + const bool use_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER); + const int required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime; + + /* Sculpt can skip certain modifiers. */ MultiresModifierData *mmd = get_multires_modifier(scene, ob, 0); const bool has_multires = (mmd && mmd->sculptlvl != 0); bool multires_applied = false; - const bool sculpt_mode = ob->mode & OB_MODE_SCULPT && ob->sculpt && !useRenderParams; - const bool sculpt_dyntopo = (sculpt_mode && ob->sculpt->bm) && !useRenderParams; + const bool sculpt_mode = ob->mode & OB_MODE_SCULPT && ob->sculpt && !use_render; + const bool sculpt_dyntopo = (sculpt_mode && ob->sculpt->bm) && !use_render; - /* Generic preview only in object mode! */ - const bool do_mod_mcol = (ob->mode == OB_MODE_OBJECT); - const bool do_loop_normals = ((((Mesh *)ob->data)->flag & ME_AUTOSMOOTH) != 0 || - (dataMask->lmask & CD_MASK_NORMAL) != 0); - /* Some modifiers may need this info from their target (other) object, simpler to generate it here as well. - * Note that they will always be generated when no loop normals are comptuted, - * since they are needed by drawing code. */ - const bool do_poly_normals = ((dataMask->pmask & CD_MASK_NORMAL) != 0); + /* Modifier evaluation contexts for different types of modifiers. */ + ModifierApplyFlag app_render = use_render ? MOD_APPLY_RENDER : 0; + ModifierApplyFlag app_cache = use_cache ? MOD_APPLY_USECACHE : 0; + const ModifierEvalContext mectx = {depsgraph, ob, app_render | app_cache}; + const ModifierEvalContext mectx_orco = {depsgraph, ob, app_render | MOD_APPLY_ORCO}; + /* Get effective list of modifiers to execute. Some effects like shape keys + * are added as virtual modifiers before the user created modifiers. */ VirtualModifierData virtualModifierData; + ModifierData *firstmd = modifiers_getVirtualModifierList(ob, &virtualModifierData); + ModifierData *md = firstmd; - ModifierApplyFlag app_flags = useRenderParams ? MOD_APPLY_RENDER : 0; - ModifierApplyFlag deform_app_flags = app_flags; - - BLI_assert((((Mesh *)ob->data)->id.tag & LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT) == 0); - - if (useCache) - app_flags |= MOD_APPLY_USECACHE; - if (useDeform) - deform_app_flags |= MOD_APPLY_USECACHE; - - /* TODO(sybren): do we really need three context objects? Or do we modify - * them on the fly to change the flags where needed? */ - const ModifierEvalContext mectx_deform = {depsgraph, ob, deform_app_flags}; - const ModifierEvalContext mectx_apply = {depsgraph, ob, app_flags}; - const ModifierEvalContext mectx_orco = {depsgraph, ob, (app_flags & ~MOD_APPLY_USECACHE) | MOD_APPLY_ORCO}; - - md = firstmd = modifiers_getVirtualModifierList(ob, &virtualModifierData); - - modifiers_clearErrors(ob); - + /* Preview colors by modifiers such as dynamic paint, to show the results + * even if the resulting data is not used in a material. Only in object mode. + * TODO: this is broken, not drawn by the drawn manager. */ + const bool do_mod_mcol = (ob->mode == OB_MODE_OBJECT); + ModifierData *previewmd = NULL; + CustomData_MeshMasks previewmask = {0}; if (do_mod_mcol) { /* Find the last active modifier generating a preview, or NULL if none. */ /* XXX Currently, DPaint modifier just ignores this. @@ -1058,21 +1115,21 @@ static void mesh_calc_modifiers( previewmd = modifiers_getLastPreview(scene, md, required_mode); } - datamasks = modifiers_calcDataMasks(scene, ob, md, dataMask, required_mode, previewmd, &previewmask); - curr = datamasks; - - if (r_deform) { - *r_deform = NULL; - } - *r_final = NULL; + /* Compute accumulated datamasks needed by each modifier. It helps to do + * this fine grained so that for example vertex groups are preserved up to + * an armature modifier, but not through a following subsurf modifier where + * subdividing them is expensive. */ + CDMaskLink *datamasks = modifiers_calcDataMasks(scene, ob, md, dataMask, required_mode, previewmd, &previewmask); + CDMaskLink *md_datamask = datamasks; + /* XXX Always copying POLYINDEX, else tessellated data are no more valid! */ + CustomData_MeshMasks append_mask = CD_MASK_BAREMESH_ORIGINDEX; - /* We need mesh even for deform-only part of the stack, in cases where some modifier needs - * e.g. access to updated normals. See T62633 for an example. */ - Mesh *me = NULL; + /* Clear errors before evaluation. */ + modifiers_clearErrors(ob); + /* Apply all leading deform modifiers. */ if (useDeform) { - /* Apply all leading deforming modifiers */ - for (; md; md = md->next, curr = curr->next) { + for (; md; md = md->next, md_datamask = md_datamask->next) { const ModifierTypeInfo *mti = modifierType_getInfo(md->type); if (!modifier_isEnabled(scene, md, required_mode)) { @@ -1084,19 +1141,18 @@ static void mesh_calc_modifiers( } if (mti->type == eModifierTypeType_OnlyDeform && !sculpt_dyntopo) { - if (!deformedVerts) { - deformedVerts = BKE_mesh_vertexCos_get(ob->data, &numVerts); + if (!deformed_verts) { + deformed_verts = BKE_mesh_vertexCos_get(mesh_input, &num_deformed_verts); } - - if (isPrevDeform && mti->dependsOnNormals && mti->dependsOnNormals(md)) { - if (me == NULL) { - me = BKE_mesh_copy_for_eval(ob->data, true); - ASSERT_IS_VALID_MESH(me); + else if (isPrevDeform && mti->dependsOnNormals && mti->dependsOnNormals(md)) { + if (mesh_final == NULL) { + mesh_final = BKE_mesh_copy_for_eval(mesh_input, true); + ASSERT_IS_VALID_MESH(mesh_final); } - BKE_mesh_apply_vert_coords(me, deformedVerts); + BKE_mesh_apply_vert_coords(mesh_final, deformed_verts); } - modwrap_deformVerts(md, &mectx_deform, me, deformedVerts, numVerts); + modwrap_deformVerts(md, &mectx, mesh_final, deformed_verts, num_deformed_verts); isPrevDeform = true; } @@ -1111,29 +1167,18 @@ static void mesh_calc_modifiers( /* Result of all leading deforming modifiers is cached for * places that wish to use the original mesh but with deformed - * coordinates (vpaint, etc.) - */ + * coordinates (like vertex paint). */ if (r_deform) { - *r_deform = BKE_mesh_copy_for_eval(ob->data, true); + mesh_deform = BKE_mesh_copy_for_eval(mesh_input, true); - if (deformedVerts) { - BKE_mesh_apply_vert_coords(*r_deform, deformedVerts); + if (deformed_verts) { + BKE_mesh_apply_vert_coords(mesh_deform, deformed_verts); } } } - else { - /* default behavior for meshes */ - deformedVerts = BKE_mesh_vertexCos_get(ob->data, &numVerts); - } - - - /* Now apply all remaining modifiers. If useDeform is off then skip - * OnlyDeform ones. - */ - Mesh *me_orco = NULL; - Mesh *me_orco_cloth = NULL; - for (; md; md = md->next, curr = curr->next) { + /* Apply all remaining constructive and deforming modifiers. */ + for (; md; md = md->next, md_datamask = md_datamask->next) { const ModifierTypeInfo *mti = modifierType_getInfo(md->type); if (!modifier_isEnabled(scene, md, required_mode)) { @@ -1144,7 +1189,7 @@ static void mesh_calc_modifiers( continue; } - if ((mti->flags & eModifierTypeFlag_RequiresOriginalData) && me) { + if ((mti->flags & eModifierTypeFlag_RequiresOriginalData) && mesh_final) { modifier_setError(md, "Modifier requires original data, bad stack position"); continue; } @@ -1161,7 +1206,7 @@ static void mesh_calc_modifiers( } } - if (sculpt_dyntopo && !useRenderParams) + if (sculpt_dyntopo) unsupported = true; if (scene->toolsettings->sculpt->flags & SCULPT_ONLY_DEFORM) @@ -1189,91 +1234,87 @@ static void mesh_calc_modifiers( continue; } - /* add an orco layer if needed by this modifier */ - memset(&mask, 0, sizeof(mask)); - if (mti->requiredDataMask) { + /* Add an orco layer if needed by this modifier. */ + if (mesh_final && mti->requiredDataMask) { + CustomData_MeshMasks mask = {0}; mti->requiredDataMask(ob, md, &mask); - } - - if (me && (mask.vmask & CD_MASK_ORCO)) { - add_orco_mesh(ob, NULL, me, me_orco, CD_ORCO); + if (mask.vmask & CD_MASK_ORCO) { + add_orco_mesh(ob, NULL, mesh_final, mesh_orco, CD_ORCO); + } } /* How to apply modifier depends on (a) what we already have as * a result of previous modifiers (could be a Mesh or just - * deformed vertices) and (b) what type the modifier is. - */ - + * deformed vertices) and (b) what type the modifier is. */ if (mti->type == eModifierTypeType_OnlyDeform) { /* No existing verts to deform, need to build them. */ - if (!deformedVerts) { - if (me) { + if (!deformed_verts) { + if (mesh_final) { /* Deforming a mesh, read the vertex locations * out of the mesh and deform them. Once done with this - * run of deformers verts will be written back. - */ - deformedVerts = BKE_mesh_vertexCos_get(me, &numVerts); + * run of deformers verts will be written back. */ + deformed_verts = BKE_mesh_vertexCos_get(mesh_final, &num_deformed_verts); } else { - deformedVerts = BKE_mesh_vertexCos_get(ob->data, &numVerts); + deformed_verts = BKE_mesh_vertexCos_get(mesh_input, &num_deformed_verts); } } - /* if this is not the last modifier in the stack then recalculate the normals * to avoid giving bogus normals to the next modifier see: [#23673] */ - if (isPrevDeform && mti->dependsOnNormals && mti->dependsOnNormals(md)) { + else if (isPrevDeform && mti->dependsOnNormals && mti->dependsOnNormals(md)) { /* XXX, this covers bug #23673, but we may need normal calc for other types */ - if (me) { - BKE_mesh_apply_vert_coords(me, deformedVerts); + if (mesh_final) { + BKE_mesh_apply_vert_coords(mesh_final, deformed_verts); } } - modwrap_deformVerts(md, &mectx_deform, me, deformedVerts, numVerts); + modwrap_deformVerts(md, &mectx, mesh_final, deformed_verts, num_deformed_verts); } else { /* determine which data layers are needed by following modifiers */ - if (curr->next) - nextmask = curr->next->mask; + CustomData_MeshMasks nextmask; + if (md_datamask->next) + nextmask = md_datamask->next->mask; else nextmask = *dataMask; /* apply vertex coordinates or build a Mesh as necessary */ - if (me) { - if (deformedVerts) { - BKE_mesh_apply_vert_coords(me, deformedVerts); + if (mesh_final) { + if (deformed_verts) { + BKE_mesh_apply_vert_coords(mesh_final, deformed_verts); } } else { - me = BKE_mesh_copy_for_eval(ob->data, true); - ASSERT_IS_VALID_MESH(me); + mesh_final = BKE_mesh_copy_for_eval(mesh_input, true); + ASSERT_IS_VALID_MESH(mesh_final); - if (deformedVerts) { - BKE_mesh_apply_vert_coords(me, deformedVerts); + if (deformed_verts) { + BKE_mesh_apply_vert_coords(mesh_final, deformed_verts); } - /* Constructive modifiers need to have an origindex - * otherwise they wont have anywhere to copy the data from. + /* Initialize original indices the first time we evaluate a + * constructive modifier. Modifiers will then do mapping mostly + * automatic by copying them through CustomData_copy_data along + * with other data. * - * Also create ORIGINDEX data if any of the following modifiers - * requests it, this way Mirror, Solidify etc will keep ORIGINDEX - * data by using generic DM_copy_vert_data() functions. - */ + * These are created when either requested by evaluation, or if + * following modifiers requested them. */ if (need_mapping || ((nextmask.vmask | nextmask.emask | nextmask.pmask) & CD_MASK_ORIGINDEX)) { /* calc */ - CustomData_add_layer(&me->vdata, CD_ORIGINDEX, CD_CALLOC, NULL, me->totvert); - CustomData_add_layer(&me->edata, CD_ORIGINDEX, CD_CALLOC, NULL, me->totedge); - CustomData_add_layer(&me->pdata, CD_ORIGINDEX, CD_CALLOC, NULL, me->totpoly); + CustomData_add_layer(&mesh_final->vdata, CD_ORIGINDEX, CD_CALLOC, NULL, mesh_final->totvert); + CustomData_add_layer(&mesh_final->edata, CD_ORIGINDEX, CD_CALLOC, NULL, mesh_final->totedge); + CustomData_add_layer(&mesh_final->pdata, CD_ORIGINDEX, CD_CALLOC, NULL, mesh_final->totpoly); /* Not worth parallelizing this, gives less than 0.1% overall speedup in best of best cases... */ - range_vn_i(CustomData_get_layer(&me->vdata, CD_ORIGINDEX), me->totvert, 0); - range_vn_i(CustomData_get_layer(&me->edata, CD_ORIGINDEX), me->totedge, 0); - range_vn_i(CustomData_get_layer(&me->pdata, CD_ORIGINDEX), me->totpoly, 0); + range_vn_i(CustomData_get_layer(&mesh_final->vdata, CD_ORIGINDEX), mesh_final->totvert, 0); + range_vn_i(CustomData_get_layer(&mesh_final->edata, CD_ORIGINDEX), mesh_final->totedge, 0); + range_vn_i(CustomData_get_layer(&mesh_final->pdata, CD_ORIGINDEX), mesh_final->totpoly, 0); } } /* set the Mesh to only copy needed data */ - mask = curr->mask; + CustomData_MeshMasks mask = md_datamask->mask; /* needMapping check here fixes bug [#28112], otherwise it's * possible that it won't be copied */ CustomData_MeshMasks_update(&mask, &append_mask); @@ -1282,44 +1323,44 @@ static void mesh_calc_modifiers( mask.emask |= CD_MASK_ORIGINDEX; mask.pmask |= CD_MASK_ORIGINDEX; } - mesh_set_only_copy(me, &mask); + mesh_set_only_copy(mesh_final, &mask); /* add cloth rest shape key if needed */ if (mask.vmask & CD_MASK_CLOTH_ORCO) { - add_orco_mesh(ob, NULL, me, me_orco, CD_CLOTH_ORCO); + add_orco_mesh(ob, NULL, mesh_final, mesh_orco, CD_CLOTH_ORCO); } /* add an origspace layer if needed */ - if ((curr->mask.lmask) & CD_MASK_ORIGSPACE_MLOOP) { - if (!CustomData_has_layer(&me->ldata, CD_ORIGSPACE_MLOOP)) { - CustomData_add_layer(&me->ldata, CD_ORIGSPACE_MLOOP, CD_CALLOC, NULL, me->totloop); - mesh_init_origspace(me); + if ((md_datamask->mask.lmask) & CD_MASK_ORIGSPACE_MLOOP) { + if (!CustomData_has_layer(&mesh_final->ldata, CD_ORIGSPACE_MLOOP)) { + CustomData_add_layer(&mesh_final->ldata, CD_ORIGSPACE_MLOOP, CD_CALLOC, NULL, mesh_final->totloop); + mesh_init_origspace(mesh_final); } } - Mesh *me_next = modwrap_applyModifier(md, &mectx_apply, me); - ASSERT_IS_VALID_MESH(me_next); + Mesh *mesh_next = modwrap_applyModifier(md, &mectx, mesh_final); + ASSERT_IS_VALID_MESH(mesh_next); - if (me_next) { + if (mesh_next) { /* if the modifier returned a new mesh, release the old one */ - if (me && me != me_next) { - BLI_assert(me != ob->data); - BKE_id_free(NULL, me); + if (mesh_final != mesh_next) { + BLI_assert(mesh_final != mesh_input); + BKE_id_free(NULL, mesh_final); } - me = me_next; + mesh_final = mesh_next; - if (deformedVerts) { - MEM_freeN(deformedVerts); - deformedVerts = NULL; + if (deformed_verts) { + MEM_freeN(deformed_verts); + deformed_verts = NULL; } - mesh_copy_autosmooth(me, ob->data); + mesh_copy_autosmooth(mesh_final, mesh_input); } /* create an orco mesh in parallel */ if (nextmask.vmask & CD_MASK_ORCO) { - if (!me_orco) { - me_orco = create_orco_mesh(ob, ob->data, NULL, CD_ORCO); + if (!mesh_orco) { + mesh_orco = create_orco_mesh(ob, mesh_input, NULL, CD_ORCO); } nextmask.vmask &= ~CD_MASK_ORCO; @@ -1333,45 +1374,45 @@ static void mesh_calc_modifiers( mti->requiredDataMask(ob, md, &temp_cddata_masks); } CustomData_MeshMasks_update(&temp_cddata_masks, &nextmask); - mesh_set_only_copy(me_orco, &temp_cddata_masks); + mesh_set_only_copy(mesh_orco, &temp_cddata_masks); - me_next = modwrap_applyModifier(md, &mectx_orco, me_orco); - ASSERT_IS_VALID_MESH(me_next); + mesh_next = modwrap_applyModifier(md, &mectx_orco, mesh_orco); + ASSERT_IS_VALID_MESH(mesh_next); - if (me_next) { + if (mesh_next) { /* if the modifier returned a new mesh, release the old one */ - if (me_orco && me_orco != me_next) { - BLI_assert(me_orco != ob->data); - BKE_id_free(NULL, me_orco); + if (mesh_orco != mesh_next) { + BLI_assert(mesh_orco != mesh_input); + BKE_id_free(NULL, mesh_orco); } - me_orco = me_next; + mesh_orco = mesh_next; } } /* create cloth orco mesh in parallel */ if (nextmask.vmask & CD_MASK_CLOTH_ORCO) { - if (!me_orco_cloth) { - me_orco_cloth = create_orco_mesh(ob, ob->data, NULL, CD_CLOTH_ORCO); + if (!mesh_orco_cloth) { + mesh_orco_cloth = create_orco_mesh(ob, mesh_input, NULL, CD_CLOTH_ORCO); } nextmask.vmask &= ~CD_MASK_CLOTH_ORCO; nextmask.vmask |= CD_MASK_ORIGINDEX; nextmask.emask |= CD_MASK_ORIGINDEX; nextmask.pmask |= CD_MASK_ORIGINDEX; - mesh_set_only_copy(me_orco_cloth, &nextmask); + mesh_set_only_copy(mesh_orco_cloth, &nextmask); - me_next = modwrap_applyModifier(md, &mectx_orco, me_orco_cloth); - ASSERT_IS_VALID_MESH(me_next); + mesh_next = modwrap_applyModifier(md, &mectx_orco, mesh_orco_cloth); + ASSERT_IS_VALID_MESH(mesh_next); - if (me_next) { + if (mesh_next) { /* if the modifier returned a new mesh, release the old one */ - if (me_orco_cloth && me_orco_cloth != me_next) { - BLI_assert(me_orco != ob->data); - BKE_id_free(NULL, me_orco_cloth); + if (mesh_orco_cloth != mesh_next) { + BLI_assert(mesh_orco != mesh_input); + BKE_id_free(NULL, mesh_orco_cloth); } - me_orco_cloth = me_next; + mesh_orco_cloth = mesh_next; } } @@ -1381,7 +1422,7 @@ static void mesh_calc_modifiers( append_mask.lmask |= CD_MASK_PREVIEW_MLOOPCOL; } - me->runtime.deformed_only = false; + mesh_final->runtime.deformed_only = false; } isPrevDeform = (mti->type == eModifierTypeType_OnlyDeform); @@ -1395,85 +1436,46 @@ static void mesh_calc_modifiers( } } + BLI_linklist_free((LinkNode *)datamasks, NULL); + for (md = firstmd; md; md = md->next) modifier_freeTemporaryData(md); /* Yay, we are done. If we have a Mesh and deformed vertices * need to apply these back onto the Mesh. If we have no - * Mesh then we need to build one. - */ - if (me) { - *r_final = me; - - if (deformedVerts) { - BKE_mesh_apply_vert_coords(*r_final, deformedVerts); - } + * Mesh then we need to build one. */ + if (mesh_final == NULL) { + mesh_final = BKE_mesh_copy_for_eval(mesh_input, true); } - else { - *r_final = BKE_mesh_copy_for_eval(ob->data, true); - - if (deformedVerts) { - BKE_mesh_apply_vert_coords(*r_final, deformedVerts); - } + if (deformed_verts) { + BKE_mesh_apply_vert_coords(mesh_final, deformed_verts); + MEM_freeN(deformed_verts); + deformed_verts = NULL; } - /* add an orco layer if needed */ + /* Add orco coordinates to final and deformed mesh if requested. */ if (dataMask->vmask & CD_MASK_ORCO) { - add_orco_mesh(ob, NULL, *r_final, me_orco, CD_ORCO); + add_orco_mesh(ob, NULL, mesh_final, mesh_orco, CD_ORCO); - if (r_deform && *r_deform) - add_orco_mesh(ob, NULL, *r_deform, NULL, CD_ORCO); + if (mesh_deform) + add_orco_mesh(ob, NULL, mesh_deform, NULL, CD_ORCO); } - if (do_loop_normals) { - /* In case we also need poly normals, add the layer here, then BKE_mesh_calc_normals_split() will fill it. */ - if (do_poly_normals) { - if (!CustomData_has_layer(&(*r_final)->pdata, CD_NORMAL)) { - CustomData_add_layer(&(*r_final)->pdata, CD_NORMAL, CD_CALLOC, NULL, (*r_final)->totpoly); - } - } - /* Compute loop normals (note: will compute poly and vert normals as well, if needed!) */ - BKE_mesh_calc_normals_split(*r_final); - BKE_mesh_tessface_clear(*r_final); + if (mesh_orco) { + BKE_id_free(NULL, mesh_orco); } - - if (sculpt_dyntopo == false) { - /* watch this! after 2.75a we move to from tessface to looptri (by default) */ - if (dataMask->fmask & CD_MASK_MFACE) { - BKE_mesh_tessface_ensure(*r_final); - } - - /* without this, drawing ngon tri's faces will show ugly tessellated face - * normals and will also have to calculate normals on the fly, try avoid - * this where possible since calculating polygon normals isn't fast, - * note that this isn't a problem for subsurf (only quads) or editmode - * which deals with drawing differently. - * - * Only calc vertex normals if they are flagged as dirty. - * If using loop normals, poly nors have already been computed. - */ - if (!do_loop_normals) { - BKE_mesh_ensure_normals_for_display(*r_final); - } + if (mesh_orco_cloth) { + BKE_id_free(NULL, mesh_orco_cloth); } - /* Some modifiers, like datatransfer, may generate those data as temp layer, we do not want to keep them, - * as they are used by display code when available (i.e. even if autosmooth is disabled). */ - if (!do_loop_normals && CustomData_has_layer(&(*r_final)->ldata, CD_NORMAL)) { - CustomData_free_layers(&(*r_final)->ldata, CD_NORMAL, (*r_final)->totloop); - } + /* Compute normals. */ + mesh_calc_modifier_final_normals(mesh_input, dataMask, sculpt_dyntopo, mesh_final); - if (me_orco) { - BKE_id_free(NULL, me_orco); - } - if (me_orco_cloth) { - BKE_id_free(NULL, me_orco_cloth); + /* Return final mesh */ + *r_final = mesh_final; + if (r_deform) { + *r_deform = mesh_deform; } - - if (deformedVerts) - MEM_freeN(deformedVerts); - - BLI_linklist_free((LinkNode *)datamasks, NULL); } @@ -1512,213 +1514,264 @@ bool editbmesh_modifier_is_enabled(Scene *scene, ModifierData *md, bool has_prev return true; } +static void editbmesh_calc_modifier_final_normals( + const Mesh *mesh_input, + const CustomData_MeshMasks *dataMask, + Mesh *mesh_final) +{ + const bool do_loop_normals = ((mesh_input->flag & ME_AUTOSMOOTH) != 0 || + (dataMask->lmask & CD_MASK_NORMAL) != 0); + /* Some modifiers may need this info from their target (other) object, simpler to generate it here as well. */ + const bool do_poly_normals = ((dataMask->pmask & CD_MASK_NORMAL) != 0); + + if (do_loop_normals) { + /* In case we also need poly normals, add the layer here, then BKE_mesh_calc_normals_split() will fill it. */ + if (do_poly_normals) { + if (!CustomData_has_layer(&mesh_final->pdata, CD_NORMAL)) { + CustomData_add_layer(&mesh_final->pdata, CD_NORMAL, CD_CALLOC, NULL, mesh_final->totpoly); + } + } + /* Compute loop normals */ + BKE_mesh_calc_normals_split(mesh_final); + BKE_mesh_tessface_clear(mesh_final); + } + + /* BMESH_ONLY, ensure tessface's used for drawing, + * but don't recalculate if the last modifier in the stack gives us tessfaces + * check if the derived meshes are DM_TYPE_EDITBMESH before calling, this isn't essential + * but quiets annoying error messages since tessfaces wont be created. */ + if (dataMask->fmask & CD_MASK_MFACE) { + if (mesh_final->edit_mesh == NULL) { + BKE_mesh_tessface_ensure(mesh_final); + } + } + + /* same as mesh_calc_modifiers (if using loop normals, poly nors have already been computed). */ + if (!do_loop_normals) { + BKE_mesh_ensure_normals_for_display(mesh_final); + + /* Some modifiers, like datatransfer, may generate those data, we do not want to keep them, + * as they are used by display code when available (i.e. even if autosmooth is disabled). */ + if (CustomData_has_layer(&mesh_final->ldata, CD_NORMAL)) { + CustomData_free_layers(&mesh_final->ldata, CD_NORMAL, mesh_final->totloop); + } + } +} + static void editbmesh_calc_modifiers( struct Depsgraph *depsgraph, Scene *scene, Object *ob, - BMEditMesh *em, + BMEditMesh *em_input, const CustomData_MeshMasks *dataMask, /* return args */ Mesh **r_cage, Mesh **r_final) { - ModifierData *md; - float (*deformedVerts)[3] = NULL; - CustomData_MeshMasks mask = {0}, append_mask = CD_MASK_BAREMESH; - int i, numVerts = 0, cageIndex = modifiers_getCageIndex(scene, ob, NULL, 1); - CDMaskLink *datamasks, *curr; - const int required_mode = eModifierMode_Realtime | eModifierMode_Editmode; - const bool do_init_statvis = false; /* FIXME: use V3D_OVERLAY_EDIT_STATVIS. */ - VirtualModifierData virtualModifierData; + /* Input and final mesh. Final mesh is only created the moment the first + * constructive modifier is executed, or a deform modifier needs normals + * or certain data layers. */ + Mesh *mesh_input = ob->data; + Mesh *mesh_final = NULL; + Mesh *mesh_cage = NULL; + + /* Deformed vertex locations array. Deform only modifier need this type of + * float array rather than MVert*. Tracked along with mesh_final as an + * optimization to avoid copying coordinates back and forth if there are + * multiple sequential deform only modifiers. */ + float (*deformed_verts)[3] = NULL; + int num_deformed_verts = 0; bool isPrevDeform = false; - /* TODO(sybren): do we really need multiple objects, or shall we change the flags where needed? */ - const ModifierEvalContext mectx = {depsgraph, ob, 0}; - const ModifierEvalContext mectx_orco = {depsgraph, ob, MOD_APPLY_ORCO}; - const ModifierEvalContext mectx_cache = {depsgraph, ob, MOD_APPLY_USECACHE}; + /* Mesh with constructive modifiers but no deformation applied. Tracked + * along with final mesh if undeformed / orco coordinates are requested + * for texturing. */ + Mesh *mesh_orco = NULL; - const bool do_loop_normals = ((((Mesh *)(ob->data))->flag & ME_AUTOSMOOTH) != 0 || - (dataMask->lmask & CD_MASK_NORMAL) != 0); - /* Some modifiers may need this info from their target (other) object, simpler to generate it here as well. */ - const bool do_poly_normals = ((dataMask->pmask & CD_MASK_NORMAL) != 0); + /* Modifier evaluation modes. */ + const int required_mode = eModifierMode_Realtime | eModifierMode_Editmode; + const bool do_init_statvis = false; /* FIXME: use V3D_OVERLAY_EDIT_STATVIS. */ - modifiers_clearErrors(ob); + /* Modifier evaluation contexts for different types of modifiers. */ + const ModifierEvalContext mectx = {depsgraph, ob, MOD_APPLY_USECACHE}; + const ModifierEvalContext mectx_orco = {depsgraph, ob, MOD_APPLY_ORCO}; + /* Evaluate modifiers up to certain index to get the mesh cage. */ + int cageIndex = modifiers_getCageIndex(scene, ob, NULL, 1); if (r_cage && cageIndex == -1) { - *r_cage = BKE_mesh_from_editmesh_with_coords_thin_wrap(em, dataMask, NULL); - mesh_copy_autosmooth(*r_cage, ob->data); + mesh_cage = BKE_mesh_from_editmesh_with_coords_thin_wrap(em_input, dataMask, NULL); + mesh_copy_autosmooth(mesh_cage, mesh_input); } - md = modifiers_getVirtualModifierList(ob, &virtualModifierData); - - /* copied from mesh_calc_modifiers */ - datamasks = modifiers_calcDataMasks(scene, ob, md, dataMask, required_mode, NULL, NULL); + /* Get effective list of modifiers to execute. Some effects like shape keys + * are added as virtual modifiers before the user created modifiers. */ + VirtualModifierData virtualModifierData; + ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); - curr = datamasks; + /* Compute accumulated datamasks needed by each modifier. It helps to do + * this fine grained so that for example vertex groups are preserved up to + * an armature modifier, but not through a following subsurf modifier where + * subdividing them is expensive. */ + CDMaskLink *datamasks = modifiers_calcDataMasks(scene, ob, md, dataMask, required_mode, NULL, NULL); + CDMaskLink *md_datamask = datamasks; + CustomData_MeshMasks append_mask = CD_MASK_BAREMESH; - Mesh *me = NULL; - Mesh *me_orco = NULL; + /* Clear errors before evaluation. */ + modifiers_clearErrors(ob); - for (i = 0; md; i++, md = md->next, curr = curr->next) { + for (int i = 0; md; i++, md = md->next, md_datamask = md_datamask->next) { const ModifierTypeInfo *mti = modifierType_getInfo(md->type); - memset(&mask, 0, sizeof(mask)); - if (!editbmesh_modifier_is_enabled(scene, md, me != NULL)) { + if (!editbmesh_modifier_is_enabled(scene, md, mesh_final != NULL)) { continue; } - /* add an orco layer if needed by this modifier */ - if (me && mti->requiredDataMask) { + /* Add an orco layer if needed by this modifier. */ + if (mesh_final && mti->requiredDataMask) { + CustomData_MeshMasks mask = {0}; mti->requiredDataMask(ob, md, &mask); if (mask.vmask & CD_MASK_ORCO) { - add_orco_mesh(ob, em, me, me_orco, CD_ORCO); + add_orco_mesh(ob, em_input, mesh_final, mesh_orco, CD_ORCO); } } /* How to apply modifier depends on (a) what we already have as - * a result of previous modifiers (could be a DerivedMesh or just - * deformed vertices) and (b) what type the modifier is. - */ - + * a result of previous modifiers (could be a mesh or just + * deformed vertices) and (b) what type the modifier is. */ if (mti->type == eModifierTypeType_OnlyDeform) { /* No existing verts to deform, need to build them. */ - if (!deformedVerts) { - if (me) { + if (!deformed_verts) { + if (mesh_final) { /* Deforming a derived mesh, read the vertex locations * out of the mesh and deform them. Once done with this - * run of deformers verts will be written back. - */ - deformedVerts = BKE_mesh_vertexCos_get(me, &numVerts); + * run of deformers verts will be written back. */ + deformed_verts = BKE_mesh_vertexCos_get(mesh_final, &num_deformed_verts); } else { - deformedVerts = editbmesh_get_vertex_cos(em, &numVerts); + deformed_verts = editbmesh_get_vertex_cos(em_input, &num_deformed_verts); } } - - if (isPrevDeform && mti->dependsOnNormals && mti->dependsOnNormals(md)) { - if (me == NULL) { - me = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL); - ASSERT_IS_VALID_MESH(me); - mesh_copy_autosmooth(me, ob->data); + else if (isPrevDeform && mti->dependsOnNormals && mti->dependsOnNormals(md)) { + if (mesh_final == NULL) { + mesh_final = BKE_mesh_from_bmesh_for_eval_nomain(em_input->bm, NULL); + ASSERT_IS_VALID_MESH(mesh_final); + mesh_copy_autosmooth(mesh_final, mesh_input); } - BLI_assert(deformedVerts != NULL); - BKE_mesh_apply_vert_coords(me, deformedVerts); + BLI_assert(deformed_verts != NULL); + BKE_mesh_apply_vert_coords(mesh_final, deformed_verts); } if (mti->deformVertsEM) - modwrap_deformVertsEM(md, &mectx, em, me, deformedVerts, numVerts); + modwrap_deformVertsEM(md, &mectx, em_input, mesh_final, deformed_verts, num_deformed_verts); else - modwrap_deformVerts(md, &mectx, me, deformedVerts, numVerts); + modwrap_deformVerts(md, &mectx, mesh_final, deformed_verts, num_deformed_verts); } else { - Mesh *me_next; - /* apply vertex coordinates or build a DerivedMesh as necessary */ - if (me) { - if (deformedVerts) { - Mesh *me_temp = BKE_mesh_copy_for_eval(me, false); - - if (!(r_cage && me == *r_cage)) { - BKE_id_free(NULL, me); + if (mesh_final) { + if (deformed_verts) { + Mesh *mesh_tmp = BKE_mesh_copy_for_eval(mesh_final, false); + if (mesh_final != mesh_cage) { + BKE_id_free(NULL, mesh_final); } - me = me_temp; - BKE_mesh_apply_vert_coords(me, deformedVerts); + mesh_final = mesh_tmp; + BKE_mesh_apply_vert_coords(mesh_final, deformed_verts); } - else if (r_cage && me == *r_cage) { + else if (mesh_final == mesh_cage) { /* 'me' may be changed by this modifier, so we need to copy it. */ - me = BKE_mesh_copy_for_eval(me, false); + mesh_final = BKE_mesh_copy_for_eval(mesh_final, false); } } else { - me = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL); - ASSERT_IS_VALID_MESH(me); + mesh_final = BKE_mesh_from_bmesh_for_eval_nomain(em_input->bm, NULL); + ASSERT_IS_VALID_MESH(mesh_final); - mesh_copy_autosmooth(me, ob->data); + mesh_copy_autosmooth(mesh_final, mesh_input); - if (deformedVerts) { - BKE_mesh_apply_vert_coords(me, deformedVerts); + if (deformed_verts) { + BKE_mesh_apply_vert_coords(mesh_final, deformed_verts); } } /* create an orco derivedmesh in parallel */ - mask = curr->mask; + CustomData_MeshMasks mask = md_datamask->mask; if (mask.vmask & CD_MASK_ORCO) { - if (!me_orco) { - me_orco = create_orco_mesh(ob, ob->data, em, CD_ORCO); + if (!mesh_orco) { + mesh_orco = create_orco_mesh(ob, mesh_input, em_input, CD_ORCO); } mask.vmask &= ~CD_MASK_ORCO; mask.vmask |= CD_MASK_ORIGINDEX; mask.emask |= CD_MASK_ORIGINDEX; mask.pmask |= CD_MASK_ORIGINDEX; - mesh_set_only_copy(me_orco, &mask); + mesh_set_only_copy(mesh_orco, &mask); - me_next = modwrap_applyModifier(md, &mectx_orco, me_orco); - ASSERT_IS_VALID_MESH(me_next); + Mesh *mesh_next = modwrap_applyModifier(md, &mectx_orco, mesh_orco); + ASSERT_IS_VALID_MESH(mesh_next); - if (me_next) { + if (mesh_next) { /* if the modifier returned a new dm, release the old one */ - if (me_orco && me_orco != me_next) { - BKE_id_free(NULL, me_orco); + if (mesh_orco && mesh_orco != mesh_next) { + BKE_id_free(NULL, mesh_orco); } - me_orco = me_next; + mesh_orco = mesh_next; } } /* set the DerivedMesh to only copy needed data */ CustomData_MeshMasks_update(&mask, &append_mask); - mask = curr->mask; /* CD_MASK_ORCO may have been cleared above */ /* XXX WHAT? ovewrites mask ??? */ + mask = md_datamask->mask; /* CD_MASK_ORCO may have been cleared above */ /* XXX WHAT? ovewrites mask ??? */ mask.vmask |= CD_MASK_ORIGINDEX; mask.emask |= CD_MASK_ORIGINDEX; mask.pmask |= CD_MASK_ORIGINDEX; - mesh_set_only_copy(me, &mask); + mesh_set_only_copy(mesh_final, &mask); if (mask.lmask & CD_MASK_ORIGSPACE_MLOOP) { - if (!CustomData_has_layer(&me->ldata, CD_ORIGSPACE_MLOOP)) { - CustomData_add_layer(&me->ldata, CD_ORIGSPACE_MLOOP, CD_CALLOC, NULL, me->totloop); - mesh_init_origspace(me); + if (!CustomData_has_layer(&mesh_final->ldata, CD_ORIGSPACE_MLOOP)) { + CustomData_add_layer(&mesh_final->ldata, CD_ORIGSPACE_MLOOP, CD_CALLOC, NULL, mesh_final->totloop); + mesh_init_origspace(mesh_final); } } - me_next = modwrap_applyModifier(md, &mectx_cache, me); - ASSERT_IS_VALID_MESH(me_next); + Mesh *mesh_next = modwrap_applyModifier(md, &mectx, mesh_final); + ASSERT_IS_VALID_MESH(mesh_next); - if (me_next) { - if (me && me != me_next) { - BKE_id_free(NULL, me); + if (mesh_next) { + if (mesh_final && mesh_final != mesh_next) { + BKE_id_free(NULL, mesh_final); } - me = me_next; + mesh_final = mesh_next; - if (deformedVerts) { - MEM_freeN(deformedVerts); - deformedVerts = NULL; + if (deformed_verts) { + MEM_freeN(deformed_verts); + deformed_verts = NULL; } - mesh_copy_autosmooth(me, ob->data); + mesh_copy_autosmooth(mesh_final, mesh_input); } - me->runtime.deformed_only = false; + mesh_final->runtime.deformed_only = false; } if (r_cage && i == cageIndex) { - if (me && deformedVerts) { - *r_cage = BKE_mesh_copy_for_eval(me, false); - BKE_mesh_apply_vert_coords(*r_cage, deformedVerts); + if (mesh_final && deformed_verts) { + mesh_cage = BKE_mesh_copy_for_eval(mesh_final, false); + BKE_mesh_apply_vert_coords(mesh_cage, deformed_verts); } - else if (me) { - *r_cage = me; + else if (mesh_final) { + mesh_cage = mesh_final; } else { - Mesh *me_orig = ob->data; + Mesh *me_orig = mesh_input; if (me_orig->id.tag & LIB_TAG_COPIED_ON_WRITE) { BKE_mesh_runtime_ensure_edit_data(me_orig); - me_orig->runtime.edit_data->vertexCos = MEM_dupallocN(deformedVerts); + me_orig->runtime.edit_data->vertexCos = MEM_dupallocN(deformed_verts); } - *r_cage = BKE_mesh_from_editmesh_with_coords_thin_wrap( - em, &mask, - deformedVerts ? MEM_dupallocN(deformedVerts) : NULL); - mesh_copy_autosmooth(*r_cage, ob->data); + mesh_cage = BKE_mesh_from_editmesh_with_coords_thin_wrap( + em_input, dataMask, + deformed_verts ? MEM_dupallocN(deformed_verts) : NULL); + mesh_copy_autosmooth(mesh_cage, mesh_input); } } @@ -1729,22 +1782,20 @@ static void editbmesh_calc_modifiers( /* Yay, we are done. If we have a DerivedMesh and deformed vertices need * to apply these back onto the DerivedMesh. If we have no DerivedMesh - * then we need to build one. - */ - if (me && deformedVerts) { - *r_final = BKE_mesh_copy_for_eval(me, false); - - if (!(r_cage && me == *r_cage)) { - BKE_id_free(NULL, me); + * then we need to build one. */ + if (mesh_final) { + if (deformed_verts) { + Mesh *mesh_tmp = BKE_mesh_copy_for_eval(mesh_final, false); + if (mesh_final != mesh_cage) { + BKE_id_free(NULL, mesh_final); + } + BKE_mesh_apply_vert_coords(mesh_final, deformed_verts); + mesh_final = mesh_tmp; } - BKE_mesh_apply_vert_coords(*r_final, deformedVerts); } - else if (me) { - *r_final = me; - } - else if (!deformedVerts && r_cage && *r_cage) { + else if (!deformed_verts && mesh_cage) { /* cage should already have up to date normals */ - *r_final = *r_cage; + mesh_final = mesh_cage; /* In this case, we should never have weight-modifying modifiers in stack... */ if (do_init_statvis) { @@ -1753,10 +1804,10 @@ static void editbmesh_calc_modifiers( } else { /* this is just a copy of the editmesh, no need to calc normals */ - *r_final = BKE_mesh_from_editmesh_with_coords_thin_wrap(em, dataMask, deformedVerts); - deformedVerts = NULL; + mesh_final = BKE_mesh_from_editmesh_with_coords_thin_wrap(em_input, dataMask, deformed_verts); + deformed_verts = NULL; - mesh_copy_autosmooth(*r_final, ob->data); + mesh_copy_autosmooth(mesh_final, mesh_input); /* In this case, we should never have weight-modifying modifiers in stack... */ if (do_init_statvis) { @@ -1764,73 +1815,29 @@ static void editbmesh_calc_modifiers( } } - if (do_loop_normals) { - /* In case we also need poly normals, add the layer here, then BKE_mesh_calc_normals_split() will fill it. */ - if (do_poly_normals) { - if (!CustomData_has_layer(&(*r_final)->pdata, CD_NORMAL)) { - CustomData_add_layer(&(*r_final)->pdata, CD_NORMAL, CD_CALLOC, NULL, (*r_final)->totpoly); - } - if (r_cage && *r_cage && (*r_cage != *r_final)) { - if (!CustomData_has_layer(&(*r_cage)->pdata, CD_NORMAL)) { - CustomData_add_layer(&(*r_cage)->pdata, CD_NORMAL, CD_CALLOC, NULL, (*r_cage)->totpoly); - } - } - } - /* Compute loop normals */ - BKE_mesh_calc_normals_split(*r_final); - BKE_mesh_tessface_clear(*r_final); - if (r_cage && *r_cage && (*r_cage != *r_final)) { - BKE_mesh_calc_normals_split(*r_cage); - BKE_mesh_tessface_clear(*r_cage); - } + if (deformed_verts) { + MEM_freeN(deformed_verts); } - /* BMESH_ONLY, ensure tessface's used for drawing, - * but don't recalculate if the last modifier in the stack gives us tessfaces - * check if the derived meshes are DM_TYPE_EDITBMESH before calling, this isn't essential - * but quiets annoying error messages since tessfaces wont be created. */ - if (dataMask->fmask & CD_MASK_MFACE) { - if ((*r_final)->edit_mesh == NULL) { - BKE_mesh_tessface_ensure(*r_final); - } - if (r_cage && *r_cage) { - if ((*r_cage)->edit_mesh == NULL) { - if (*r_cage != *r_final) { - BKE_mesh_tessface_ensure(*r_cage); - } - } - } + /* Add orco coordinates to final and deformed mesh if requested. */ + if (dataMask->vmask & CD_MASK_ORCO) { + add_orco_mesh(ob, em_input, mesh_final, mesh_orco, CD_ORCO); } - /* --- */ - - /* same as mesh_calc_modifiers (if using loop normals, poly nors have already been computed). */ - if (!do_loop_normals) { - BKE_mesh_ensure_normals_for_display(*r_final); - - if (r_cage && *r_cage && (*r_cage != *r_final)) { - BKE_mesh_ensure_normals_for_display(*r_cage); - } - /* Some modifiers, like datatransfer, may generate those data, we do not want to keep them, - * as they are used by display code when available (i.e. even if autosmooth is disabled). */ - if (CustomData_has_layer(&(*r_final)->ldata, CD_NORMAL)) { - CustomData_free_layers(&(*r_final)->ldata, CD_NORMAL, (*r_final)->totloop); - } - if (r_cage && CustomData_has_layer(&(*r_cage)->ldata, CD_NORMAL)) { - CustomData_free_layers(&(*r_cage)->ldata, CD_NORMAL, (*r_cage)->totloop); - } + if (mesh_orco) { + BKE_id_free(NULL, mesh_orco); } - /* add an orco layer if needed */ - if (dataMask->vmask & CD_MASK_ORCO) - add_orco_mesh(ob, em, *r_final, me_orco, CD_ORCO); - - if (me_orco) { - BKE_id_free(NULL, me_orco); + /* Compute normals. */ + editbmesh_calc_modifier_final_normals(mesh_input, dataMask, mesh_final); + if (mesh_cage && (mesh_cage != mesh_final)) { + editbmesh_calc_modifier_final_normals(mesh_input, dataMask, mesh_cage); } - if (deformedVerts) { - MEM_freeN(deformedVerts); + /* Return final mesh. */ + *r_final = mesh_final; + if (r_cage) { + *r_cage = mesh_cage; } } -- cgit v1.2.3