Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenkernel/intern/DerivedMesh.cc
| Show First 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | |||||
| #include "BLI_utildefines.h" | #include "BLI_utildefines.h" | ||||
| #include "BLI_vector.hh" | #include "BLI_vector.hh" | ||||
| #include "BKE_DerivedMesh.h" | #include "BKE_DerivedMesh.h" | ||||
| #include "BKE_bvhutils.h" | #include "BKE_bvhutils.h" | ||||
| #include "BKE_colorband.h" | #include "BKE_colorband.h" | ||||
| #include "BKE_deform.h" | #include "BKE_deform.h" | ||||
| #include "BKE_editmesh.h" | #include "BKE_editmesh.h" | ||||
| #include "BKE_geometry_set.hh" | |||||
| #include "BKE_key.h" | #include "BKE_key.h" | ||||
| #include "BKE_layer.h" | #include "BKE_layer.h" | ||||
| #include "BKE_lib_id.h" | #include "BKE_lib_id.h" | ||||
| #include "BKE_material.h" | #include "BKE_material.h" | ||||
| #include "BKE_mesh.h" | #include "BKE_mesh.h" | ||||
| #include "BKE_mesh_iterators.h" | #include "BKE_mesh_iterators.h" | ||||
| #include "BKE_mesh_mapping.h" | #include "BKE_mesh_mapping.h" | ||||
| #include "BKE_mesh_runtime.h" | #include "BKE_mesh_runtime.h" | ||||
| ▲ Show 20 Lines • Show All 815 Lines • ▼ Show 20 Lines | |||||
| { | { | ||||
| if (me_eval->runtime.wrapper_type_finalize & (1 << ME_WRAPPER_TYPE_BMESH)) { | if (me_eval->runtime.wrapper_type_finalize & (1 << ME_WRAPPER_TYPE_BMESH)) { | ||||
| editbmesh_calc_modifier_final_normals(me_eval, cd_mask_finalize); | editbmesh_calc_modifier_final_normals(me_eval, cd_mask_finalize); | ||||
| me_eval->runtime.wrapper_type_finalize &= ~(1 << ME_WRAPPER_TYPE_BMESH); | me_eval->runtime.wrapper_type_finalize &= ~(1 << ME_WRAPPER_TYPE_BMESH); | ||||
| } | } | ||||
| BLI_assert(me_eval->runtime.wrapper_type_finalize == 0); | BLI_assert(me_eval->runtime.wrapper_type_finalize == 0); | ||||
| } | } | ||||
| /** | |||||
| * Modifies the given mesh and geometry set. The geometry set is expect to have NO mesh component. | |||||
| * After this function ends, the geometry set will still have NO mesh component. Instead, an input | |||||
| * mesh is passed separately and is returned separately. | |||||
| * | |||||
| * The purpose of the geometry set is to store all non-mesh geometry components that are generated | |||||
| * by modifiers. | |||||
| */ | |||||
| static Mesh *modifier_modify_mesh_and_geometry_set(ModifierData *md, | |||||
| const ModifierEvalContext &mectx, | |||||
| Object *ob, | |||||
| Mesh *input_mesh, | |||||
| GeometrySet &geometry_set) | |||||
| { | |||||
| Mesh *mesh_output = nullptr; | |||||
| const ModifierTypeInfo *mti = BKE_modifier_get_info((ModifierType)md->type); | |||||
| if (mti->modifyGeometrySet == nullptr) { | |||||
| mesh_output = BKE_modifier_modify_mesh(md, &mectx, input_mesh); | |||||
| } | |||||
| else { | |||||
| BKE_mesh_wrapper_ensure_mdata(input_mesh); | |||||
brecht: For performance reasons, at some point we should move this deeper into the nodes, so that we… | |||||
| /* Adds a new mesh component to the geometry set based on the #input_mesh. */ | |||||
| BLI_assert(!geometry_set.has<MeshComponent>()); | |||||
| MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>(); | |||||
| mesh_component.replace(input_mesh, GeometryOwnershipType::Editable); | |||||
| mesh_component.copy_vertex_group_names_from_object(*ob); | |||||
| /* Let the modifier change the geometry set. */ | |||||
| mti->modifyGeometrySet(md, &mectx, &geometry_set); | |||||
| /* Release the mesh from the geometry set again. */ | |||||
| if (geometry_set.has<MeshComponent>()) { | |||||
| MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>(); | |||||
| mesh_output = mesh_component.release(); | |||||
| geometry_set.remove<MeshComponent>(); | |||||
| } | |||||
| /* Return an empty mesh instead of null. */ | |||||
| if (mesh_output == nullptr) { | |||||
| mesh_output = BKE_mesh_new_nomain(0, 0, 0, 0, 0); | |||||
| BKE_mesh_copy_settings(mesh_output, input_mesh); | |||||
| } | |||||
| } | |||||
| return mesh_output; | |||||
| } | |||||
| static void mesh_calc_modifiers(struct Depsgraph *depsgraph, | static void mesh_calc_modifiers(struct Depsgraph *depsgraph, | ||||
| Scene *scene, | Scene *scene, | ||||
| Object *ob, | Object *ob, | ||||
| int useDeform, | int useDeform, | ||||
| const bool need_mapping, | const bool need_mapping, | ||||
| const CustomData_MeshMasks *dataMask, | const CustomData_MeshMasks *dataMask, | ||||
| const int index, | const int index, | ||||
| const bool use_cache, | const bool use_cache, | ||||
| const bool allow_shared_mesh, | const bool allow_shared_mesh, | ||||
| /* return args */ | /* return args */ | ||||
| Mesh **r_deform, | Mesh **r_deform, | ||||
| Mesh **r_final) | Mesh **r_final, | ||||
| GeometrySet **r_geometry_set) | |||||
| { | { | ||||
| /* Input and final mesh. Final mesh is only created the moment the first | /* Input and final mesh. Final mesh is only created the moment the first | ||||
| * constructive modifier is executed, or a deform modifier needs normals | * constructive modifier is executed, or a deform modifier needs normals | ||||
| * or certain data layers. */ | * or certain data layers. */ | ||||
| Mesh *mesh_input = (Mesh *)ob->data; | Mesh *mesh_input = (Mesh *)ob->data; | ||||
| Mesh *mesh_final = nullptr; | Mesh *mesh_final = nullptr; | ||||
| Mesh *mesh_deform = nullptr; | Mesh *mesh_deform = nullptr; | ||||
| /* This geometry set contains the non-mesh data that might be generated by modifiers. */ | |||||
| GeometrySet geometry_set_final; | |||||
| BLI_assert((mesh_input->id.tag & LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT) == 0); | 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 | /* Deformed vertex locations array. Deform only modifier need this type of | ||||
| * float array rather than MVert*. Tracked along with mesh_final as an | * float array rather than MVert*. Tracked along with mesh_final as an | ||||
| * optimization to avoid copying coordinates back and forth if there are | * optimization to avoid copying coordinates back and forth if there are | ||||
| * multiple sequential deform only modifiers. */ | * multiple sequential deform only modifiers. */ | ||||
| float(*deformed_verts)[3] = nullptr; | float(*deformed_verts)[3] = nullptr; | ||||
| int num_deformed_verts = mesh_input->totvert; | int num_deformed_verts = mesh_input->totvert; | ||||
| ▲ Show 20 Lines • Show All 281 Lines • ▼ Show 20 Lines | else { | ||||
| if ((md_datamask->mask.lmask) & CD_MASK_ORIGSPACE_MLOOP) { | if ((md_datamask->mask.lmask) & CD_MASK_ORIGSPACE_MLOOP) { | ||||
| if (!CustomData_has_layer(&mesh_final->ldata, CD_ORIGSPACE_MLOOP)) { | if (!CustomData_has_layer(&mesh_final->ldata, CD_ORIGSPACE_MLOOP)) { | ||||
| CustomData_add_layer( | CustomData_add_layer( | ||||
| &mesh_final->ldata, CD_ORIGSPACE_MLOOP, CD_CALLOC, nullptr, mesh_final->totloop); | &mesh_final->ldata, CD_ORIGSPACE_MLOOP, CD_CALLOC, nullptr, mesh_final->totloop); | ||||
| mesh_init_origspace(mesh_final); | mesh_init_origspace(mesh_final); | ||||
| } | } | ||||
| } | } | ||||
| Mesh *mesh_next = BKE_modifier_modify_mesh(md, &mectx, mesh_final); | Mesh *mesh_next = modifier_modify_mesh_and_geometry_set( | ||||
| md, mectx, ob, mesh_final, geometry_set_final); | |||||
| ASSERT_IS_VALID_MESH(mesh_next); | ASSERT_IS_VALID_MESH(mesh_next); | ||||
| if (mesh_next) { | if (mesh_next) { | ||||
| /* if the modifier returned a new mesh, release the old one */ | /* if the modifier returned a new mesh, release the old one */ | ||||
| if (mesh_final != mesh_next) { | if (mesh_final != mesh_next) { | ||||
| BLI_assert(mesh_final != mesh_input); | BLI_assert(mesh_final != mesh_input); | ||||
| BKE_id_free(nullptr, mesh_final); | BKE_id_free(nullptr, mesh_final); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 161 Lines • ▼ Show 20 Lines | if (is_own_mesh) { | ||||
| mesh_calc_finalize(mesh_input, mesh_final); | mesh_calc_finalize(mesh_input, mesh_final); | ||||
| } | } | ||||
| /* Return final mesh */ | /* Return final mesh */ | ||||
| *r_final = mesh_final; | *r_final = mesh_final; | ||||
| if (r_deform) { | if (r_deform) { | ||||
| *r_deform = mesh_deform; | *r_deform = mesh_deform; | ||||
| } | } | ||||
| if (r_geometry_set) { | |||||
| *r_geometry_set = new GeometrySet(std::move(geometry_set_final)); | |||||
| } | |||||
| } | } | ||||
| float (*editbmesh_vert_coords_alloc(BMEditMesh *em, int *r_vert_len))[3] | float (*editbmesh_vert_coords_alloc(BMEditMesh *em, int *r_vert_len))[3] | ||||
| { | { | ||||
| BMIter iter; | BMIter iter; | ||||
| BMVert *eve; | BMVert *eve; | ||||
| float(*cos)[3]; | float(*cos)[3]; | ||||
| int i; | int i; | ||||
| ▲ Show 20 Lines • Show All 92 Lines • ▼ Show 20 Lines | |||||
| static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, | static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, | ||||
| Scene *scene, | Scene *scene, | ||||
| Object *ob, | Object *ob, | ||||
| BMEditMesh *em_input, | BMEditMesh *em_input, | ||||
| const CustomData_MeshMasks *dataMask, | const CustomData_MeshMasks *dataMask, | ||||
| /* return args */ | /* return args */ | ||||
| Mesh **r_cage, | Mesh **r_cage, | ||||
| Mesh **r_final) | Mesh **r_final, | ||||
| GeometrySet **r_geometry_set) | |||||
| { | { | ||||
| /* Input and final mesh. Final mesh is only created the moment the first | /* Input and final mesh. Final mesh is only created the moment the first | ||||
| * constructive modifier is executed, or a deform modifier needs normals | * constructive modifier is executed, or a deform modifier needs normals | ||||
| * or certain data layers. */ | * or certain data layers. */ | ||||
| Mesh *mesh_input = (Mesh *)ob->data; | Mesh *mesh_input = (Mesh *)ob->data; | ||||
| Mesh *mesh_final = nullptr; | Mesh *mesh_final = nullptr; | ||||
| Mesh *mesh_cage = nullptr; | Mesh *mesh_cage = nullptr; | ||||
| /* This geometry set contains the non-mesh data that might be generated by modifiers. */ | |||||
| GeometrySet geometry_set_final; | |||||
| /* Deformed vertex locations array. Deform only modifier need this type of | /* Deformed vertex locations array. Deform only modifier need this type of | ||||
| * float array rather than MVert*. Tracked along with mesh_final as an | * float array rather than MVert*. Tracked along with mesh_final as an | ||||
| * optimization to avoid copying coordinates back and forth if there are | * optimization to avoid copying coordinates back and forth if there are | ||||
| * multiple sequential deform only modifiers. */ | * multiple sequential deform only modifiers. */ | ||||
| float(*deformed_verts)[3] = nullptr; | float(*deformed_verts)[3] = nullptr; | ||||
| int num_deformed_verts = 0; | int num_deformed_verts = 0; | ||||
| bool isPrevDeform = false; | bool isPrevDeform = false; | ||||
| ▲ Show 20 Lines • Show All 148 Lines • ▼ Show 20 Lines | else { | ||||
| if (mask.lmask & CD_MASK_ORIGSPACE_MLOOP) { | if (mask.lmask & CD_MASK_ORIGSPACE_MLOOP) { | ||||
| if (!CustomData_has_layer(&mesh_final->ldata, CD_ORIGSPACE_MLOOP)) { | if (!CustomData_has_layer(&mesh_final->ldata, CD_ORIGSPACE_MLOOP)) { | ||||
| CustomData_add_layer( | CustomData_add_layer( | ||||
| &mesh_final->ldata, CD_ORIGSPACE_MLOOP, CD_CALLOC, nullptr, mesh_final->totloop); | &mesh_final->ldata, CD_ORIGSPACE_MLOOP, CD_CALLOC, nullptr, mesh_final->totloop); | ||||
| mesh_init_origspace(mesh_final); | mesh_init_origspace(mesh_final); | ||||
| } | } | ||||
| } | } | ||||
| Mesh *mesh_next = BKE_modifier_modify_mesh(md, &mectx, mesh_final); | Mesh *mesh_next = modifier_modify_mesh_and_geometry_set( | ||||
| md, mectx, ob, mesh_final, geometry_set_final); | |||||
| ASSERT_IS_VALID_MESH(mesh_next); | ASSERT_IS_VALID_MESH(mesh_next); | ||||
| if (mesh_next) { | if (mesh_next) { | ||||
| if (mesh_final && mesh_final != mesh_next) { | if (mesh_final && mesh_final != mesh_next) { | ||||
| BKE_id_free(nullptr, mesh_final); | BKE_id_free(nullptr, mesh_final); | ||||
| } | } | ||||
| mesh_final = mesh_next; | mesh_final = mesh_next; | ||||
| ▲ Show 20 Lines • Show All 85 Lines • ▼ Show 20 Lines | if (mesh_cage && (mesh_cage != mesh_final)) { | ||||
| editbmesh_calc_modifier_final_normals(mesh_cage, &final_datamask); | editbmesh_calc_modifier_final_normals(mesh_cage, &final_datamask); | ||||
| } | } | ||||
| /* Return final mesh. */ | /* Return final mesh. */ | ||||
| *r_final = mesh_final; | *r_final = mesh_final; | ||||
| if (r_cage) { | if (r_cage) { | ||||
| *r_cage = mesh_cage; | *r_cage = mesh_cage; | ||||
| } | } | ||||
| if (r_geometry_set) { | |||||
| *r_geometry_set = new GeometrySet(std::move(geometry_set_final)); | |||||
| } | |||||
| } | } | ||||
| static void mesh_build_extra_data(struct Depsgraph *depsgraph, Object *ob, Mesh *mesh_eval) | static void mesh_build_extra_data(struct Depsgraph *depsgraph, Object *ob, Mesh *mesh_eval) | ||||
| { | { | ||||
| uint32_t eval_flags = DEG_get_eval_flags_for_id(depsgraph, &ob->id); | uint32_t eval_flags = DEG_get_eval_flags_for_id(depsgraph, &ob->id); | ||||
| if (eval_flags & DAG_EVAL_NEED_SHRINKWRAP_BOUNDARY) { | if (eval_flags & DAG_EVAL_NEED_SHRINKWRAP_BOUNDARY) { | ||||
| BKE_shrinkwrap_compute_boundary_data(mesh_eval); | BKE_shrinkwrap_compute_boundary_data(mesh_eval); | ||||
| Show All 30 Lines | if (need_mapping) { | ||||
| /* Also add the flag so that it is recorded in lastDataMask. */ | /* Also add the flag so that it is recorded in lastDataMask. */ | ||||
| dataMask->vmask |= CD_MASK_ORIGINDEX; | dataMask->vmask |= CD_MASK_ORIGINDEX; | ||||
| dataMask->emask |= CD_MASK_ORIGINDEX; | dataMask->emask |= CD_MASK_ORIGINDEX; | ||||
| dataMask->pmask |= CD_MASK_ORIGINDEX; | dataMask->pmask |= CD_MASK_ORIGINDEX; | ||||
| } | } | ||||
| #endif | #endif | ||||
| Mesh *mesh_eval = nullptr, *mesh_deform_eval = nullptr; | Mesh *mesh_eval = nullptr, *mesh_deform_eval = nullptr; | ||||
| GeometrySet *geometry_set_eval = nullptr; | |||||
| mesh_calc_modifiers(depsgraph, | mesh_calc_modifiers(depsgraph, | ||||
| scene, | scene, | ||||
| ob, | ob, | ||||
| 1, | 1, | ||||
| need_mapping, | need_mapping, | ||||
| dataMask, | dataMask, | ||||
| -1, | -1, | ||||
| true, | true, | ||||
| true, | true, | ||||
| &mesh_deform_eval, | &mesh_deform_eval, | ||||
| &mesh_eval); | &mesh_eval, | ||||
| &geometry_set_eval); | |||||
| /* The modifier stack evaluation is storing result in mesh->runtime.mesh_eval, but this result | /* The modifier stack evaluation is storing result in mesh->runtime.mesh_eval, but this result | ||||
| * is not guaranteed to be owned by object. | * is not guaranteed to be owned by object. | ||||
| * | * | ||||
| * Check ownership now, since later on we can not go to a mesh owned by someone else via | * Check ownership now, since later on we can not go to a mesh owned by someone else via | ||||
| * object's runtime: this could cause access freed data on depsgraph destruction (mesh who owns | * object's runtime: this could cause access freed data on depsgraph destruction (mesh who owns | ||||
| * the final result might be freed prior to object). */ | * the final result might be freed prior to object). */ | ||||
| Mesh *mesh = (Mesh *)ob->data; | Mesh *mesh = (Mesh *)ob->data; | ||||
| const bool is_mesh_eval_owned = (mesh_eval != mesh->runtime.mesh_eval); | const bool is_mesh_eval_owned = (mesh_eval != mesh->runtime.mesh_eval); | ||||
| BKE_object_eval_assign_data(ob, &mesh_eval->id, is_mesh_eval_owned); | BKE_object_eval_assign_data(ob, &mesh_eval->id, is_mesh_eval_owned); | ||||
| /* Add the final mesh as read-only non-owning component to the geometry set. */ | |||||
| BLI_assert(!geometry_set_eval->has<MeshComponent>()); | |||||
| MeshComponent &mesh_component = geometry_set_eval->get_component_for_write<MeshComponent>(); | |||||
| mesh_component.replace(mesh_eval, GeometryOwnershipType::ReadOnly); | |||||
| ob->runtime.geometry_set_eval = geometry_set_eval; | |||||
| ob->runtime.mesh_deform_eval = mesh_deform_eval; | ob->runtime.mesh_deform_eval = mesh_deform_eval; | ||||
| ob->runtime.last_data_mask = *dataMask; | ob->runtime.last_data_mask = *dataMask; | ||||
| ob->runtime.last_need_mapping = need_mapping; | ob->runtime.last_need_mapping = need_mapping; | ||||
| BKE_object_boundbox_calc_from_mesh(ob, mesh_eval); | BKE_object_boundbox_calc_from_mesh(ob, mesh_eval); | ||||
| /* Make sure that drivers can target shapekey properties. | /* Make sure that drivers can target shapekey properties. | ||||
| * Note that this causes a potential inconsistency, as the shapekey may have a | * Note that this causes a potential inconsistency, as the shapekey may have a | ||||
| Show All 23 Lines | static void editbmesh_build_data(struct Depsgraph *depsgraph, | ||||
| if (DEG_is_active(depsgraph)) { | if (DEG_is_active(depsgraph)) { | ||||
| BKE_sculpt_update_object_before_eval(obedit); | BKE_sculpt_update_object_before_eval(obedit); | ||||
| } | } | ||||
| BKE_editmesh_free_derivedmesh(em); | BKE_editmesh_free_derivedmesh(em); | ||||
| Mesh *me_cage; | Mesh *me_cage; | ||||
| Mesh *me_final; | Mesh *me_final; | ||||
| GeometrySet *non_mesh_components; | |||||
| editbmesh_calc_modifiers(depsgraph, scene, obedit, em, dataMask, &me_cage, &me_final); | editbmesh_calc_modifiers( | ||||
| depsgraph, scene, obedit, em, dataMask, &me_cage, &me_final, &non_mesh_components); | |||||
| em->mesh_eval_final = me_final; | em->mesh_eval_final = me_final; | ||||
| em->mesh_eval_cage = me_cage; | em->mesh_eval_cage = me_cage; | ||||
| obedit->runtime.geometry_set_eval = non_mesh_components; | |||||
| BKE_object_boundbox_calc_from_mesh(obedit, em->mesh_eval_final); | BKE_object_boundbox_calc_from_mesh(obedit, em->mesh_eval_final); | ||||
| em->lastDataMask = *dataMask; | em->lastDataMask = *dataMask; | ||||
| mesh_runtime_check_normals_valid(em->mesh_eval_final); | mesh_runtime_check_normals_valid(em->mesh_eval_final); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 135 Lines • ▼ Show 20 Lines | |||||
| Mesh *mesh_create_eval_final(Depsgraph *depsgraph, | Mesh *mesh_create_eval_final(Depsgraph *depsgraph, | ||||
| Scene *scene, | Scene *scene, | ||||
| Object *ob, | Object *ob, | ||||
| const CustomData_MeshMasks *dataMask) | const CustomData_MeshMasks *dataMask) | ||||
| { | { | ||||
| Mesh *final; | Mesh *final; | ||||
| mesh_calc_modifiers(depsgraph, scene, ob, 1, false, dataMask, -1, false, false, nullptr, &final); | mesh_calc_modifiers( | ||||
| depsgraph, scene, ob, 1, false, dataMask, -1, false, false, nullptr, &final, nullptr); | |||||
| return final; | return final; | ||||
| } | } | ||||
| Mesh *mesh_create_eval_final_index_render(Depsgraph *depsgraph, | Mesh *mesh_create_eval_final_index_render(Depsgraph *depsgraph, | ||||
| Scene *scene, | Scene *scene, | ||||
| Object *ob, | Object *ob, | ||||
| const CustomData_MeshMasks *dataMask, | const CustomData_MeshMasks *dataMask, | ||||
| int index) | int index) | ||||
| { | { | ||||
| Mesh *final; | Mesh *final; | ||||
| mesh_calc_modifiers( | mesh_calc_modifiers( | ||||
| depsgraph, scene, ob, 1, false, dataMask, index, false, false, nullptr, &final); | depsgraph, scene, ob, 1, false, dataMask, index, false, false, nullptr, &final, nullptr); | ||||
| return final; | return final; | ||||
| } | } | ||||
| Mesh *mesh_create_eval_no_deform(Depsgraph *depsgraph, | Mesh *mesh_create_eval_no_deform(Depsgraph *depsgraph, | ||||
| Scene *scene, | Scene *scene, | ||||
| Object *ob, | Object *ob, | ||||
| const CustomData_MeshMasks *dataMask) | const CustomData_MeshMasks *dataMask) | ||||
| { | { | ||||
| Mesh *final; | Mesh *final; | ||||
| mesh_calc_modifiers(depsgraph, scene, ob, 0, false, dataMask, -1, false, false, nullptr, &final); | mesh_calc_modifiers( | ||||
| depsgraph, scene, ob, 0, false, dataMask, -1, false, false, nullptr, &final, nullptr); | |||||
| return final; | return final; | ||||
| } | } | ||||
| Mesh *mesh_create_eval_no_deform_render(Depsgraph *depsgraph, | Mesh *mesh_create_eval_no_deform_render(Depsgraph *depsgraph, | ||||
| Scene *scene, | Scene *scene, | ||||
| Object *ob, | Object *ob, | ||||
| const CustomData_MeshMasks *dataMask) | const CustomData_MeshMasks *dataMask) | ||||
| { | { | ||||
| Mesh *final; | Mesh *final; | ||||
| mesh_calc_modifiers(depsgraph, scene, ob, 0, false, dataMask, -1, false, false, nullptr, &final); | mesh_calc_modifiers( | ||||
| depsgraph, scene, ob, 0, false, dataMask, -1, false, false, nullptr, &final, nullptr); | |||||
| return final; | return final; | ||||
| } | } | ||||
| /***/ | /***/ | ||||
| Mesh *editbmesh_get_eval_cage_and_final(Depsgraph *depsgraph, | Mesh *editbmesh_get_eval_cage_and_final(Depsgraph *depsgraph, | ||||
| Scene *scene, | Scene *scene, | ||||
| ▲ Show 20 Lines • Show All 341 Lines • Show Last 20 Lines | |||||
For performance reasons, at some point we should move this deeper into the nodes, so that we don't always have to convert between mesh and editmesh. Maybe leave a comment about that.