diff options
Diffstat (limited to 'source/blender/modifiers')
22 files changed, 114 insertions, 84 deletions
diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c index 758858c8b1d..c44a4e0b438 100644 --- a/source/blender/modifiers/intern/MOD_array.c +++ b/source/blender/modifiers/intern/MOD_array.c @@ -789,13 +789,6 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd, MEM_freeN(full_doubles_map); } - /* In case org dm has dirty normals, or we made some merging, mark normals as dirty in new mesh! - * TODO: we may need to set other dirty flags as well? - */ - if (use_recalc_normals) { - BKE_mesh_normals_tag_dirty(result); - } - if (vgroup_start_cap_remap) { MEM_freeN(vgroup_start_cap_remap); } diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c index b6cceade4e2..a7364af10a3 100644 --- a/source/blender/modifiers/intern/MOD_bevel.c +++ b/source/blender/modifiers/intern/MOD_bevel.c @@ -229,8 +229,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * BM_mesh_free(bm); - BKE_mesh_normals_tag_dirty(result); - return result; } diff --git a/source/blender/modifiers/intern/MOD_boolean.cc b/source/blender/modifiers/intern/MOD_boolean.cc index 915428f99da..d47f2a130e3 100644 --- a/source/blender/modifiers/intern/MOD_boolean.cc +++ b/source/blender/modifiers/intern/MOD_boolean.cc @@ -501,7 +501,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * result = BKE_mesh_from_bmesh_for_eval_nomain(bm, nullptr, mesh); BM_mesh_free(bm); - BKE_mesh_normals_tag_dirty(result); } if (result == nullptr) { @@ -536,7 +535,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * result = BKE_mesh_from_bmesh_for_eval_nomain(bm, nullptr, mesh); BM_mesh_free(bm); - BKE_mesh_normals_tag_dirty(result); } } } diff --git a/source/blender/modifiers/intern/MOD_build.c b/source/blender/modifiers/intern/MOD_build.c index 61959d242d8..687ff04cedf 100644 --- a/source/blender/modifiers/intern/MOD_build.c +++ b/source/blender/modifiers/intern/MOD_build.c @@ -263,8 +263,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, struct MEM_freeN(edgeMap); MEM_freeN(faceMap); - BKE_mesh_normals_tag_dirty(result); - /* TODO(sybren): also copy flags & tags? */ return result; } diff --git a/source/blender/modifiers/intern/MOD_collision.c b/source/blender/modifiers/intern/MOD_collision.c index 1cb308bb2a0..593610f5bad 100644 --- a/source/blender/modifiers/intern/MOD_collision.c +++ b/source/blender/modifiers/intern/MOD_collision.c @@ -120,7 +120,7 @@ static void deformVerts(ModifierData *md, uint mvert_num = 0; BKE_mesh_vert_coords_apply(mesh_src, vertexCos); - BKE_mesh_calc_normals(mesh_src); + BKE_mesh_normals_tag_dirty(mesh_src); current_time = DEG_get_ctime(ctx->depsgraph); diff --git a/source/blender/modifiers/intern/MOD_decimate.c b/source/blender/modifiers/intern/MOD_decimate.c index 67515478be5..70f028d6907 100644 --- a/source/blender/modifiers/intern/MOD_decimate.c +++ b/source/blender/modifiers/intern/MOD_decimate.c @@ -212,8 +212,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * TIMEIT_END(decim); #endif - BKE_mesh_normals_tag_dirty(result); - return result; } diff --git a/source/blender/modifiers/intern/MOD_dynamicpaint.c b/source/blender/modifiers/intern/MOD_dynamicpaint.c index f8cf80b673c..1891ac5df7c 100644 --- a/source/blender/modifiers/intern/MOD_dynamicpaint.c +++ b/source/blender/modifiers/intern/MOD_dynamicpaint.c @@ -91,7 +91,7 @@ static void requiredDataMask(Object *UNUSED(ob), /* mcol */ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT || surface->init_color_type == MOD_DPAINT_INITIAL_VERTEXCOLOR) { - r_cddata_masks->lmask |= CD_MASK_MLOOPCOL; + r_cddata_masks->lmask |= CD_MASK_PROP_BYTE_COLOR; } /* CD_MDEFORMVERT */ if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) { diff --git a/source/blender/modifiers/intern/MOD_edgesplit.c b/source/blender/modifiers/intern/MOD_edgesplit.c index 14431e5ff2e..49ddcb9a61d 100644 --- a/source/blender/modifiers/intern/MOD_edgesplit.c +++ b/source/blender/modifiers/intern/MOD_edgesplit.c @@ -102,7 +102,6 @@ Mesh *doEdgeSplit(const Mesh *mesh, EdgeSplitModifierData *emd) result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh); BM_mesh_free(bm); - BKE_mesh_normals_tag_dirty(result); return result; } diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c index 87ff648f13d..9e2bb79138e 100644 --- a/source/blender/modifiers/intern/MOD_explode.c +++ b/source/blender/modifiers/intern/MOD_explode.c @@ -1102,7 +1102,6 @@ static Mesh *explodeMesh(ExplodeModifierData *emd, /* finalization */ BKE_mesh_calc_edges_tessface(explode); BKE_mesh_convert_mfaces_to_mpolys(explode); - BKE_mesh_normals_tag_dirty(explode); if (psmd->psys->lattice_deform_data) { BKE_lattice_deform_data_destroy(psmd->psys->lattice_deform_data); diff --git a/source/blender/modifiers/intern/MOD_mask.cc b/source/blender/modifiers/intern/MOD_mask.cc index cb26bd1b26b..900dee98268 100644 --- a/source/blender/modifiers/intern/MOD_mask.cc +++ b/source/blender/modifiers/intern/MOD_mask.cc @@ -748,7 +748,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *UNUSED(ctx) } BKE_mesh_calc_edges_loose(result); - BKE_mesh_normals_tag_dirty(result); return result; } diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index 7545bae43b3..85b6cf6a2cd 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -119,6 +119,7 @@ using blender::threading::EnumerableThreadSpecific; using namespace blender::fn::multi_function_types; using namespace blender::nodes::derived_node_tree_types; using geo_log::GeometryAttributeInfo; +using geo_log::NamedAttributeUsage; static void initData(ModifierData *md) { @@ -997,30 +998,34 @@ static void store_computed_output_attributes( const CustomDataType data_type = blender::bke::cpp_type_to_custom_data_type(store.data.type()); const std::optional<AttributeMetaData> meta_data = component.attribute_get_meta_data( store.name); - if (meta_data.has_value() && meta_data->domain == store.domain && - meta_data->data_type == data_type) { - /* Copy the data into an existing attribute. */ - blender::bke::WriteAttributeLookup write_attribute = component.attribute_try_get_for_write( - store.name); - if (write_attribute) { - write_attribute.varray.set_all(store.data.data()); - if (write_attribute.tag_modified_fn) { - write_attribute.tag_modified_fn(); - } - } - store.data.type().destruct_n(store.data.data(), store.data.size()); - MEM_freeN(store.data.data()); + + /* Attempt to remove the attribute if it already exists but the domain and type don't match. + * Removing the attribute won't succeed if it is built in and non-removable. */ + if (meta_data.has_value() && + (meta_data->domain != store.domain || meta_data->data_type != data_type)) { + component.attribute_try_delete(store.name); } - else { - /* Replace the existing attribute with the new data. */ - if (meta_data.has_value()) { - component.attribute_try_delete(store.name); - } - component.attribute_try_create(store.name, - store.domain, - blender::bke::cpp_type_to_custom_data_type(store.data.type()), - AttributeInitMove(store.data.data())); + + /* Try to create the attribute reusing the stored buffer. This will only succeed if the + * attribute didn't exist before, or if it existed but was removed above. */ + if (component.attribute_try_create( + store.name, + store.domain, + blender::bke::cpp_type_to_custom_data_type(store.data.type()), + AttributeInitMove(store.data.data()))) { + continue; + } + + OutputAttribute attribute = component.attribute_try_get_for_output_only( + store.name, store.domain, data_type); + if (attribute) { + attribute.varray().set_all(store.data.data()); + attribute.save(); } + + /* We were unable to reuse the data, so it must be destructed and freed. */ + store.data.type().destruct_n(store.data.data(), store.data.size()); + MEM_freeN(store.data.data()); } } @@ -1619,6 +1624,71 @@ static void output_attribute_panel_draw(const bContext *C, Panel *panel) } } +static void used_attributes_panel_draw(const bContext *UNUSED(C), Panel *panel) +{ + uiLayout *layout = panel->layout; + + PointerRNA *ptr = modifier_panel_get_property_pointers(panel, nullptr); + NodesModifierData *nmd = static_cast<NodesModifierData *>(ptr->data); + + if (nmd->runtime_eval_log == nullptr) { + return; + } + const geo_log::ModifierLog &log = *static_cast<geo_log::ModifierLog *>(nmd->runtime_eval_log); + Map<std::string, NamedAttributeUsage> usage_by_attribute; + log.foreach_node_log([&](const geo_log::NodeLog &node_log) { + for (const geo_log::UsedNamedAttribute &used_attribute : node_log.used_named_attributes()) { + usage_by_attribute.lookup_or_add_as(used_attribute.name, + used_attribute.usage) |= used_attribute.usage; + } + }); + + if (usage_by_attribute.is_empty()) { + uiItemL(layout, IFACE_("No named attributes used"), ICON_INFO); + return; + } + + Vector<std::pair<StringRefNull, NamedAttributeUsage>> sorted_used_attribute; + for (auto &&item : usage_by_attribute.items()) { + sorted_used_attribute.append({item.key, item.value}); + } + std::sort(sorted_used_attribute.begin(), sorted_used_attribute.end()); + + for (const auto &pair : sorted_used_attribute) { + const StringRefNull attribute_name = pair.first; + const NamedAttributeUsage usage = pair.second; + + /* #uiLayoutRowWithHeading doesn't seem to work in this case. */ + uiLayout *split = uiLayoutSplit(layout, 0.4f, false); + + std::stringstream ss; + Vector<std::string> usages; + if ((usage & NamedAttributeUsage::Read) != NamedAttributeUsage::None) { + usages.append(TIP_("Read")); + } + if ((usage & NamedAttributeUsage::Write) != NamedAttributeUsage::None) { + usages.append(TIP_("Write")); + } + if ((usage & NamedAttributeUsage::Remove) != NamedAttributeUsage::None) { + usages.append(TIP_("Remove")); + } + for (const int i : usages.index_range()) { + ss << usages[i]; + if (i < usages.size() - 1) { + ss << ", "; + } + } + + uiLayout *row = uiLayoutRow(split, false); + uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_RIGHT); + uiLayoutSetActive(row, false); + uiItemL(row, ss.str().c_str(), ICON_NONE); + + row = uiLayoutRow(split, false); + uiItemL(row, attribute_name.c_str(), ICON_NONE); + } +} + static void panelRegister(ARegionType *region_type) { PanelType *panel_type = modifier_panel_register(region_type, eModifierType_Nodes, panel_draw); @@ -1628,6 +1698,12 @@ static void panelRegister(ARegionType *region_type) nullptr, output_attribute_panel_draw, panel_type); + modifier_subpanel_register(region_type, + "used_attributes", + N_("Used Attributes"), + nullptr, + used_attributes_panel_draw, + panel_type); } static void blendWrite(BlendWriter *writer, const ModifierData *md) diff --git a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc index 68207d84015..e43d2b4ad85 100644 --- a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc +++ b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc @@ -1635,10 +1635,8 @@ class GeometryNodesEvaluator { if (conversions_.is_convertible(from_base_type, to_base_type)) { if (from_field_type->is_field(from_value)) { const GField &from_field = *from_field_type->get_field_ptr(from_value); - const MultiFunction &fn = *conversions_.get_conversion_multi_function( - MFDataType::ForSingle(from_base_type), MFDataType::ForSingle(to_base_type)); - auto operation = std::make_shared<fn::FieldOperation>(fn, Vector<GField>{from_field}); - to_field_type->construct_from_field(to_value, GField(std::move(operation), 0)); + to_field_type->construct_from_field(to_value, + conversions_.try_convert(from_field, to_base_type)); } else { to_field_type->default_construct(to_value); diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c index 6ded702ceda..b5411eee883 100644 --- a/source/blender/modifiers/intern/MOD_ocean.c +++ b/source/blender/modifiers/intern/MOD_ocean.c @@ -302,8 +302,6 @@ static Mesh *generate_ocean_geometry(OceanModifierData *omd, Mesh *mesh_orig, co } } - BKE_mesh_normals_tag_dirty(result); - return result; } @@ -361,7 +359,6 @@ static Mesh *doOcean(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mes if (omd->geometry_mode == MOD_OCEAN_GEOM_GENERATE) { result = generate_ocean_geometry(omd, mesh, resolution); - BKE_mesh_normals_tag_dirty(result); } else if (omd->geometry_mode == MOD_OCEAN_GEOM_DISPLACE) { result = (Mesh *)BKE_id_copy_ex(NULL, &mesh->id, NULL, LIB_ID_COPY_LOCALIZE); @@ -376,17 +373,17 @@ static Mesh *doOcean(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mes /* add vcols before displacement - allows lookup based on position */ if (omd->flag & MOD_OCEAN_GENERATE_FOAM) { - if (CustomData_number_of_layers(&result->ldata, CD_MLOOPCOL) < MAX_MCOL) { + if (CustomData_number_of_layers(&result->ldata, CD_PROP_BYTE_COLOR) < MAX_MCOL) { const int polys_num = result->totpoly; const int loops_num = result->totloop; MLoop *mloops = result->mloop; MLoopCol *mloopcols = CustomData_add_layer_named( - &result->ldata, CD_MLOOPCOL, CD_CALLOC, NULL, loops_num, omd->foamlayername); + &result->ldata, CD_PROP_BYTE_COLOR, CD_CALLOC, NULL, loops_num, omd->foamlayername); MLoopCol *mloopcols_spray = NULL; if (omd->flag & MOD_OCEAN_GENERATE_SPRAY) { mloopcols_spray = CustomData_add_layer_named( - &result->ldata, CD_MLOOPCOL, CD_CALLOC, NULL, loops_num, omd->spraylayername); + &result->ldata, CD_PROP_BYTE_COLOR, CD_CALLOC, NULL, loops_num, omd->spraylayername); } if (mloopcols) { /* unlikely to fail */ @@ -472,6 +469,8 @@ static Mesh *doOcean(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mes } } + BKE_mesh_normals_tag_dirty(mesh); + if (allocated_ocean) { BKE_ocean_free(omd->ocean); omd->ocean = NULL; @@ -490,15 +489,7 @@ static Mesh *doOcean(ModifierData *UNUSED(md), const ModifierEvalContext *UNUSED static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) { - Mesh *result; - - result = doOcean(md, ctx, mesh); - - if (result != mesh) { - BKE_mesh_normals_tag_dirty(result); - } - - return result; + return doOcean(md, ctx, mesh); } // #define WITH_OCEANSIM static void panel_draw(const bContext *UNUSED(C), Panel *panel) diff --git a/source/blender/modifiers/intern/MOD_particleinstance.c b/source/blender/modifiers/intern/MOD_particleinstance.c index 205a1986552..2a8d2454670 100644 --- a/source/blender/modifiers/intern/MOD_particleinstance.c +++ b/source/blender/modifiers/intern/MOD_particleinstance.c @@ -59,7 +59,7 @@ static void requiredDataMask(Object *UNUSED(ob), ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *)md; if (pimd->index_layer_name[0] != '\0' || pimd->value_layer_name[0] != '\0') { - r_cddata_masks->lmask |= CD_MASK_MLOOPCOL; + r_cddata_masks->lmask |= CD_MASK_PROP_BYTE_COLOR; } } @@ -328,9 +328,9 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * orig_mloop = mesh->mloop; MLoopCol *mloopcols_index = CustomData_get_layer_named( - &result->ldata, CD_MLOOPCOL, pimd->index_layer_name); + &result->ldata, CD_PROP_BYTE_COLOR, pimd->index_layer_name); MLoopCol *mloopcols_value = CustomData_get_layer_named( - &result->ldata, CD_MLOOPCOL, pimd->value_layer_name); + &result->ldata, CD_PROP_BYTE_COLOR, pimd->value_layer_name); int *vert_part_index = NULL; float *vert_part_value = NULL; if (mloopcols_index != NULL) { @@ -530,8 +530,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * MEM_SAFE_FREE(vert_part_index); MEM_SAFE_FREE(vert_part_value); - BKE_mesh_normals_tag_dirty(result); - return result; } diff --git a/source/blender/modifiers/intern/MOD_particlesystem.c b/source/blender/modifiers/intern/MOD_particlesystem.c index 7df7ba7c1db..032227307e7 100644 --- a/source/blender/modifiers/intern/MOD_particlesystem.c +++ b/source/blender/modifiers/intern/MOD_particlesystem.c @@ -158,7 +158,6 @@ static void deformVerts(ModifierData *md, /* make new mesh */ psmd->mesh_final = BKE_mesh_copy_for_eval(mesh_src, false); BKE_mesh_vert_coords_apply(psmd->mesh_final, vertexCos); - BKE_mesh_calc_normals(psmd->mesh_final); BKE_mesh_tessface_ensure(psmd->mesh_final); diff --git a/source/blender/modifiers/intern/MOD_remesh.c b/source/blender/modifiers/intern/MOD_remesh.c index f6f4746f44f..288faee247f 100644 --- a/source/blender/modifiers/intern/MOD_remesh.c +++ b/source/blender/modifiers/intern/MOD_remesh.c @@ -206,7 +206,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *UNUSED(ctx) BKE_mesh_copy_parameters_for_eval(result, mesh); BKE_mesh_calc_edges(result, true, false); - BKE_mesh_normals_tag_dirty(result); return result; } diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c index 4ace6404388..05072cf340c 100644 --- a/source/blender/modifiers/intern/MOD_screw.c +++ b/source/blender/modifiers/intern/MOD_screw.c @@ -384,7 +384,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * mvert_new = result->mvert; float(*vert_normals_new)[3] = BKE_mesh_vertex_normals_for_write(result); - BKE_mesh_vertex_normals_clear_dirty(result); mpoly_new = result->mpoly; mloop_new = result->mloop; medge_new = result->medge; @@ -1120,7 +1119,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * } if ((ltmd->flag & MOD_SCREW_MERGE) && (screw_ofs == 0.0f)) { - Mesh *result_prev = result; result = mesh_remove_doubles_on_axis(result, mvert_new, totvert, @@ -1128,13 +1126,10 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * axis_vec, ob_axis != NULL ? mtx_tx[3] : NULL, ltmd->merge_dist); - if (result != result_prev) { - BKE_mesh_normals_tag_dirty(result); - } } - if ((ltmd->flag & MOD_SCREW_NORMAL_CALC) == 0) { - BKE_mesh_normals_tag_dirty(result); + if ((ltmd->flag & MOD_SCREW_NORMAL_CALC)) { + BKE_mesh_vertex_normals_clear_dirty(result); } return result; diff --git a/source/blender/modifiers/intern/MOD_skin.c b/source/blender/modifiers/intern/MOD_skin.c index b950578ff1b..7f96dcb82fb 100644 --- a/source/blender/modifiers/intern/MOD_skin.c +++ b/source/blender/modifiers/intern/MOD_skin.c @@ -1950,8 +1950,6 @@ static Mesh *base_skin(Mesh *origmesh, SkinModifierData *smd, eSkinErrorFlag *r_ result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, origmesh); BM_mesh_free(bm); - BKE_mesh_normals_tag_dirty(result); - skin_set_orig_indices(result); return result; diff --git a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c index 8a84cd0a3bf..8a5b600974c 100644 --- a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c +++ b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c @@ -2016,8 +2016,6 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md, } } - BKE_mesh_normals_tag_dirty(result); - /* Make edges. */ { uint i = 0; diff --git a/source/blender/modifiers/intern/MOD_surface.c b/source/blender/modifiers/intern/MOD_surface.c index 3e75e325e44..c2869e590bd 100644 --- a/source/blender/modifiers/intern/MOD_surface.c +++ b/source/blender/modifiers/intern/MOD_surface.c @@ -129,7 +129,7 @@ static void deformVerts(ModifierData *md, MVert *x, *v; BKE_mesh_vert_coords_apply(surmd->mesh, vertexCos); - BKE_mesh_calc_normals(surmd->mesh); + BKE_mesh_normals_tag_dirty(surmd->mesh); mesh_verts_num = surmd->mesh->totvert; diff --git a/source/blender/modifiers/intern/MOD_triangulate.c b/source/blender/modifiers/intern/MOD_triangulate.c index d7e57c1f6e5..f1e8ef5bf38 100644 --- a/source/blender/modifiers/intern/MOD_triangulate.c +++ b/source/blender/modifiers/intern/MOD_triangulate.c @@ -89,8 +89,6 @@ static Mesh *triangulate_mesh(Mesh *mesh, me->flag |= ME_EDGEDRAW | ME_EDGERENDER; } - BKE_mesh_normals_tag_dirty(result); - return result; } diff --git a/source/blender/modifiers/intern/MOD_wireframe.c b/source/blender/modifiers/intern/MOD_wireframe.c index dae7d19844e..b657ea87244 100644 --- a/source/blender/modifiers/intern/MOD_wireframe.c +++ b/source/blender/modifiers/intern/MOD_wireframe.c @@ -97,8 +97,6 @@ static Mesh *WireframeModifier_do(WireframeModifierData *wmd, Object *ob, Mesh * result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh); BM_mesh_free(bm); - BKE_mesh_normals_tag_dirty(result); - return result; } |