From 54182e4925de4ee7e49e4351479e79cb257acc73 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Thu, 23 Jun 2022 12:00:25 -0500 Subject: Mesh: Add an explicit "positions changed" function We store various lazily calculated caches on meshes, some of which depend on the vertex positions staying the same. The current API to invalidate these caches is a bit confusing. With an explicit set of functions modeled after the functions in `BKE_node_tree_update.h`, it becomes clear which function to call. This may become more important if more lazy caches are added in the future. Differential Revision: https://developer.blender.org/D14760 --- source/blender/blenkernel/intern/mesh.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'source/blender/blenkernel/intern/mesh.cc') diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 7c86aff6624..ffbd824712a 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -1684,7 +1684,7 @@ void BKE_mesh_transform(Mesh *me, const float mat[4][4], bool do_keys) mul_m3_v3(m3, *lnors); } } - BKE_mesh_normals_tag_dirty(me); + BKE_mesh_tag_coords_changed(me); } void BKE_mesh_translate(Mesh *me, const float offset[3], const bool do_keys) @@ -1706,6 +1706,7 @@ void BKE_mesh_translate(Mesh *me, const float offset[3], const bool do_keys) } } } + BKE_mesh_tag_coords_changed_uniformly(me); } void BKE_mesh_tessface_ensure(Mesh *mesh) @@ -1904,7 +1905,7 @@ void BKE_mesh_vert_coords_apply(Mesh *mesh, const float (*vert_coords)[3]) for (int i = 0; i < mesh->totvert; i++, mv++) { copy_v3_v3(mv->co, vert_coords[i]); } - BKE_mesh_normals_tag_dirty(mesh); + BKE_mesh_tag_coords_changed(mesh); } void BKE_mesh_vert_coords_apply_with_mat4(Mesh *mesh, @@ -1918,7 +1919,7 @@ void BKE_mesh_vert_coords_apply_with_mat4(Mesh *mesh, for (int i = 0; i < mesh->totvert; i++, mv++) { mul_v3_m4v3(mv->co, mat, vert_coords[i]); } - BKE_mesh_normals_tag_dirty(mesh); + BKE_mesh_tag_coords_changed(mesh); } void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spacearr) -- cgit v1.2.3 From c4b32f1b291a3c3447879175225a3664aeb0b7ef Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Thu, 7 Jul 2022 22:33:57 -0500 Subject: Cleanup: Move mesh legacy conversion to a separate file It's helpful to make the separation of legacy data formats explicit, because it declutters actively changed code and makes it clear which areas do not follow Blender's current design. In this case I separated the `MFace`/"tessface" conversion code into a separate blenkernel .cc file and header. This also makes refactoring to remove these functions simpler because they're easier to find. In the future, conversions to the `MLoopUV` type and `MVert` can be implemented here for the same reasons (see T95965). Differential Revision: https://developer.blender.org/D15396 --- source/blender/blenkernel/intern/mesh.cc | 78 +------------------------------- 1 file changed, 2 insertions(+), 76 deletions(-) (limited to 'source/blender/blenkernel/intern/mesh.cc') diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index ffbd824712a..98fa551590c 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -47,6 +47,7 @@ #include "BKE_main.h" #include "BKE_material.h" #include "BKE_mesh.h" +#include "BKE_mesh_legacy_convert.h" #include "BKE_mesh_runtime.h" #include "BKE_mesh_wrapper.h" #include "BKE_modifier.h" @@ -755,7 +756,7 @@ static void mesh_ensure_tessellation_customdata(Mesh *me) if (tottex_tessface != tottex_original || totcol_tessface != totcol_original) { BKE_mesh_tessface_clear(me); - CustomData_from_bmeshpoly(&me->fdata, &me->ldata, me->totface); + BKE_mesh_add_mface_layers(&me->fdata, &me->ldata, me->totface); /* TODO: add some `--debug-mesh` option. */ if (G.debug & G_DEBUG) { @@ -1352,74 +1353,6 @@ void BKE_mesh_orco_ensure(Object *ob, Mesh *mesh) CustomData_add_layer(&mesh->vdata, CD_ORCO, CD_ASSIGN, orcodata, mesh->totvert); } -int BKE_mesh_mface_index_validate(MFace *mface, CustomData *fdata, int mfindex, int nr) -{ - /* first test if the face is legal */ - if ((mface->v3 || nr == 4) && mface->v3 == mface->v4) { - mface->v4 = 0; - nr--; - } - if ((mface->v2 || mface->v4) && mface->v2 == mface->v3) { - mface->v3 = mface->v4; - mface->v4 = 0; - nr--; - } - if (mface->v1 == mface->v2) { - mface->v2 = mface->v3; - mface->v3 = mface->v4; - mface->v4 = 0; - nr--; - } - - /* Check corrupt cases, bow-tie geometry, - * can't handle these because edge data won't exist so just return 0. */ - if (nr == 3) { - if ( - /* real edges */ - mface->v1 == mface->v2 || mface->v2 == mface->v3 || mface->v3 == mface->v1) { - return 0; - } - } - else if (nr == 4) { - if ( - /* real edges */ - mface->v1 == mface->v2 || mface->v2 == mface->v3 || mface->v3 == mface->v4 || - mface->v4 == mface->v1 || - /* across the face */ - mface->v1 == mface->v3 || mface->v2 == mface->v4) { - return 0; - } - } - - /* prevent a zero at wrong index location */ - if (nr == 3) { - if (mface->v3 == 0) { - static int corner_indices[4] = {1, 2, 0, 3}; - - SWAP(uint, mface->v1, mface->v2); - SWAP(uint, mface->v2, mface->v3); - - if (fdata) { - CustomData_swap_corners(fdata, mfindex, corner_indices); - } - } - } - else if (nr == 4) { - if (mface->v3 == 0 || mface->v4 == 0) { - static int corner_indices[4] = {2, 3, 0, 1}; - - SWAP(uint, mface->v1, mface->v3); - SWAP(uint, mface->v2, mface->v4); - - if (fdata) { - CustomData_swap_corners(fdata, mfindex, corner_indices); - } - } - } - - return nr; -} - Mesh *BKE_mesh_from_object(Object *ob) { if (ob == nullptr) { @@ -1709,13 +1642,6 @@ void BKE_mesh_translate(Mesh *me, const float offset[3], const bool do_keys) BKE_mesh_tag_coords_changed_uniformly(me); } -void BKE_mesh_tessface_ensure(Mesh *mesh) -{ - if (mesh->totpoly && mesh->totface == 0) { - BKE_mesh_tessface_calc(mesh); - } -} - void BKE_mesh_tessface_clear(Mesh *mesh) { mesh_tessface_clear_intern(mesh, true); -- cgit v1.2.3 From 05b38ecc7835b32a9f3aedf36ead4b3e41ec6ca4 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Fri, 8 Jul 2022 14:45:48 +0200 Subject: Curves: support deforming curves on surface Curves that are attached to a surface can now follow the surface when it is modified using shape keys or modifiers (but not when the original surface is deformed in edit or sculpt mode). The surface is allowed to be changed in any way that keeps uv maps intact. So deformation is allowed, but also some topology changes like subdivision. The following features are added: * A new `Deform Curves on Surface` node, which deforms curves with attachment information based on the surface object and uv map set in the properties panel. * A new `Add Rest Position` checkbox in the shape keys panel. When checked, a new `rest_position` vector attribute is added to the mesh before shape keys and modifiers are applied. This is necessary to support proper deformation of the curves, but can also be used for other purposes. * The `Add > Curve > Empty Hair` operator now sets up a simple geometry nodes setup that deforms the hair. It also makes sure that the rest position attribute is added to the surface. * A new `Object (Attach Curves to Surface)` operator in the `Set Parent To` (ctrl+P) menu, which attaches existing curves to the surface and sets the surface object as parent. Limitations: * Sculpting the procedurally deformed curves will be implemented separately. * The `Deform Curves on Surface` node is not generic and can only be used for one specific purpose currently. We plan to generalize this more in the future by adding support by exposing more inputs and/or by turning it into a node group. Differential Revision: https://developer.blender.org/D14864 --- source/blender/blenkernel/intern/mesh.cc | 34 +++++++++++++++++++------------- 1 file changed, 20 insertions(+), 14 deletions(-) (limited to 'source/blender/blenkernel/intern/mesh.cc') diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 98fa551590c..2a14370bf93 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -1848,9 +1848,25 @@ void BKE_mesh_vert_coords_apply_with_mat4(Mesh *mesh, BKE_mesh_tag_coords_changed(mesh); } -void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spacearr) +static float (*ensure_corner_normal_layer(Mesh &mesh))[3] { float(*r_loopnors)[3]; + if (CustomData_has_layer(&mesh.ldata, CD_NORMAL)) { + r_loopnors = (float(*)[3])CustomData_get_layer(&mesh.ldata, CD_NORMAL); + memset(r_loopnors, 0, sizeof(float[3]) * mesh.totloop); + } + else { + r_loopnors = (float(*)[3])CustomData_add_layer( + &mesh.ldata, CD_NORMAL, CD_CALLOC, nullptr, mesh.totloop); + CustomData_set_layer_flag(&mesh.ldata, CD_NORMAL, CD_FLAG_TEMPORARY); + } + return r_loopnors; +} + +void BKE_mesh_calc_normals_split_ex(Mesh *mesh, + MLoopNorSpaceArray *r_lnors_spacearr, + float (*r_corner_normals)[3]) +{ short(*clnors)[2] = nullptr; /* Note that we enforce computing clnors when the clnor space array is requested by caller here. @@ -1860,16 +1876,6 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spac ((mesh->flag & ME_AUTOSMOOTH) != 0); const float split_angle = (mesh->flag & ME_AUTOSMOOTH) != 0 ? mesh->smoothresh : (float)M_PI; - if (CustomData_has_layer(&mesh->ldata, CD_NORMAL)) { - r_loopnors = (float(*)[3])CustomData_get_layer(&mesh->ldata, CD_NORMAL); - memset(r_loopnors, 0, sizeof(float[3]) * mesh->totloop); - } - else { - r_loopnors = (float(*)[3])CustomData_add_layer( - &mesh->ldata, CD_NORMAL, CD_CALLOC, nullptr, mesh->totloop); - CustomData_set_layer_flag(&mesh->ldata, CD_NORMAL, CD_FLAG_TEMPORARY); - } - /* may be nullptr */ clnors = (short(*)[2])CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL); @@ -1879,7 +1885,7 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spac mesh->medge, mesh->totedge, mesh->mloop, - r_loopnors, + r_corner_normals, mesh->totloop, mesh->mpoly, BKE_mesh_poly_normals_ensure(mesh), @@ -1895,7 +1901,7 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spac void BKE_mesh_calc_normals_split(Mesh *mesh) { - BKE_mesh_calc_normals_split_ex(mesh, nullptr); + BKE_mesh_calc_normals_split_ex(mesh, nullptr, ensure_corner_normal_layer(*mesh)); } /* Split faces helper functions. */ @@ -2114,7 +2120,7 @@ void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals) MLoopNorSpaceArray lnors_spacearr = {nullptr}; /* Compute loop normals and loop normal spaces (a.k.a. smooth fans of faces around vertices). */ - BKE_mesh_calc_normals_split_ex(mesh, &lnors_spacearr); + BKE_mesh_calc_normals_split_ex(mesh, &lnors_spacearr, ensure_corner_normal_layer(*mesh)); /* Stealing memarena from loop normals space array. */ MemArena *memarena = lnors_spacearr.mem; -- cgit v1.2.3 From 8bd32019cad3cf0c5f3ce51c12612d76ee5bf04b Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 11 Jul 2022 17:25:13 +0200 Subject: Fix threading crash due to conflict in mesh wrapper type A mesh wrapper might be being accessed for read-only from one thread while another thread converts the wrapper type to something else. The proposes solution is to defer assignment of the mesh wrapper type until the wrapper is fully converted. The good thing about this approach is that it does not introduce extra synchronization (and, potentially, evaluation pipeline stalls). The downside is that it might not work with all possible wrapper types in the future. If a wrapper type which does not clear data separation is ever added in the future we will re-consider the threading safety then. Unfortunately, some changes outside of the mesh wrapper file are to be made to allow "incremental" construction of the mesh prior changing its wrapper type. Unfortunately, there is no simplified file which demonstrates the issue. It was investigated using Heist production file checked at the revision 1228: `pro/lib/char/einar/einar.shading.blend`. The repro case is simple: tab into edit mode, possibly few times. The gist is that there several surface deform and shrinkwrap modifiers which uses the same target. While one of them is building BVH tree (which changes wrapper type) the other one accesses it for read-only via `BKE_mesh_wrapper_vert_coords_copy_with_mat4()`. Differential Revision: https://developer.blender.org/D15424 --- source/blender/blenkernel/intern/mesh.cc | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'source/blender/blenkernel/intern/mesh.cc') diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 2a14370bf93..cf05dc0404e 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -1190,6 +1190,11 @@ static void ensure_orig_index_layer(CustomData &data, const int size) void BKE_mesh_ensure_default_orig_index_customdata(Mesh *mesh) { BLI_assert(mesh->runtime.wrapper_type == ME_WRAPPER_TYPE_MDATA); + BKE_mesh_ensure_default_orig_index_customdata_no_check(mesh); +} + +void BKE_mesh_ensure_default_orig_index_customdata_no_check(Mesh *mesh) +{ ensure_orig_index_layer(mesh->vdata, mesh->totvert); ensure_orig_index_layer(mesh->edata, mesh->totedge); ensure_orig_index_layer(mesh->pdata, mesh->totpoly); -- cgit v1.2.3 From c7a7aee004d96d3502d8246d9bf78f34a6dd5a0b Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 9 Aug 2022 14:18:18 +1000 Subject: Cleanup: use own username in code-comment tags --- source/blender/blenkernel/intern/mesh.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'source/blender/blenkernel/intern/mesh.cc') diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index cf05dc0404e..65f3a82eadf 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -760,10 +760,10 @@ static void mesh_ensure_tessellation_customdata(Mesh *me) /* TODO: add some `--debug-mesh` option. */ if (G.debug & G_DEBUG) { - /* NOTE(campbell): this warning may be un-called for if we are initializing the mesh for - * the first time from #BMesh, rather than giving a warning about this we could be smarter - * and check if there was any data to begin with, for now just print the warning with - * some info to help troubleshoot what's going on. */ + /* NOTE(@campbellbarton): this warning may be un-called for if we are initializing the mesh + * for the first time from #BMesh, rather than giving a warning about this we could be + * smarter and check if there was any data to begin with, for now just print the warning + * with some info to help troubleshoot what's going on. */ printf( "%s: warning! Tessellation uvs or vcol data got out of sync, " "had to reset!\n CD_MTFACE: %d != CD_MLOOPUV: %d || CD_MCOL: %d != " -- cgit v1.2.3 From 2480b55f216c31373a84bc5c5d2b0cc158497c44 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Thu, 11 Aug 2022 12:54:24 -0400 Subject: Mesh: Move hide flags to generic attributes This commit moves the hide status of mesh vertices, edges, and faces from the `ME_FLAG` to optional generic boolean attributes. Storing this data as generic attributes can significantly simplify and improve code, as described in T95965. The attributes are called `.hide_vert`, `.hide_edge`, and `.hide_poly`, using the attribute name semantics discussed in T97452. The `.` prefix means they are "UI attributes", so they still contain original data edited by users, but they aren't meant to be accessed procedurally by the user in arbitrary situations. They are also be hidden in the spreadsheet and the attribute list by default, Until 4.0, the attributes are still written to and read from the mesh in the old way, so neither forward nor backward compatibility are affected. This means memory requirements will be increased by one byte per element when the hide status is used. When the flags are removed completely, requirements will decrease when hiding is unused. Further notes: * Some code can be further simplified to skip some processing when the hide attributes don't exist. * The data is still stored in flags for `BMesh`, necessitating some complexity in the conversion to and from `Mesh`. * Access to the "hide" property of mesh elements in RNA is slower. The separate boolean arrays should be used where possible. Ref T95965 Differential Revision: https://developer.blender.org/D14685 --- source/blender/blenkernel/intern/mesh.cc | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'source/blender/blenkernel/intern/mesh.cc') diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 65f3a82eadf..abf47acd5cc 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -28,6 +28,7 @@ #include "BLI_math.h" #include "BLI_math_vector.hh" #include "BLI_memarena.h" +#include "BLI_span.hh" #include "BLI_string.h" #include "BLI_task.hh" #include "BLI_utildefines.h" @@ -36,6 +37,7 @@ #include "BLT_translation.h" #include "BKE_anim_data.h" +#include "BKE_attribute.hh" #include "BKE_bpath.h" #include "BKE_deform.h" #include "BKE_editmesh.h" @@ -62,6 +64,8 @@ #include "BLO_read_write.h" using blender::float3; +using blender::MutableSpan; +using blender::VArray; using blender::Vector; static void mesh_clear_geometry(Mesh *mesh); @@ -241,10 +245,14 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address memset(&mesh->pdata, 0, sizeof(mesh->pdata)); } else { - CustomData_blend_write_prepare(mesh->vdata, vert_layers); - CustomData_blend_write_prepare(mesh->edata, edge_layers); + if (!BLO_write_is_undo(writer)) { + BKE_mesh_legacy_convert_hide_layers_to_flags(mesh); + } + + CustomData_blend_write_prepare(mesh->vdata, vert_layers, {".hide_vert"}); + CustomData_blend_write_prepare(mesh->edata, edge_layers, {".hide_edge"}); CustomData_blend_write_prepare(mesh->ldata, loop_layers); - CustomData_blend_write_prepare(mesh->pdata, poly_layers); + CustomData_blend_write_prepare(mesh->pdata, poly_layers, {".hide_poly"}); } BLO_write_id_struct(writer, Mesh, id_address, &mesh->id); @@ -323,6 +331,10 @@ static void mesh_blend_read_data(BlendDataReader *reader, ID *id) } } + if (!BLO_read_data_is_undo(reader)) { + BKE_mesh_legacy_convert_flags_to_hide_layers(mesh); + } + /* We don't expect to load normals from files, since they are derived data. */ BKE_mesh_normals_tag_dirty(mesh); BKE_mesh_assert_normals_dirty_or_calculated(mesh); -- cgit v1.2.3 From b247588dc0f48f2fb713f6571ef0129a38760b00 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Tue, 16 Aug 2022 17:34:40 +0200 Subject: Cleanup: some refactoring in mapped mesh extraction * Flip the logic to first detect if we are dealing with an unmodified mesh in editmode. And then if not, detect if we need a mapping or not. * runtime.is_original is only valid for the bmesh wrapper. Rename it to clarify that and only check it when the mesh is a bmesh wrapper. * Remove MR_EXTRACT_MAPPED and instead check only for the existence of the origindex arrays. Previously it would sometimes access those arrays without MR_EXTRACT_MAPPED set, which according to a comment means they are invalid. Differential Revision: https://developer.blender.org/D15676 --- source/blender/blenkernel/intern/mesh.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender/blenkernel/intern/mesh.cc') diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index abf47acd5cc..1b8d094e9d3 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -113,7 +113,7 @@ static void mesh_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int * * While this could be the callers responsibility, keep here since it's * highly unlikely we want to create a duplicate and not use it for drawing. */ - mesh_dst->runtime.is_original = false; + mesh_dst->runtime.is_original_bmesh = false; /* Only do tessface if we have no polys. */ const bool do_tessface = ((mesh_src->totface != 0) && (mesh_src->totpoly == 0)); -- cgit v1.2.3 From e36ced1dce96f980fd844181946b3318fcc6233c Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Tue, 23 Aug 2022 13:50:47 -0400 Subject: Fix: Write hide status attributes for undo steps We don't convert to the old mesh format when writing undo steps to avoid overhead. So we can't skip writing the hide attributes then. --- source/blender/blenkernel/intern/mesh.cc | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'source/blender/blenkernel/intern/mesh.cc') diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 1b8d094e9d3..7f2c09f049b 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -212,6 +212,7 @@ static void mesh_foreach_path(ID *id, BPathForeachPathData *bpath_data) static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address) { + using namespace blender; Mesh *mesh = (Mesh *)id; const bool is_undo = BLO_write_is_undo(writer); @@ -245,14 +246,17 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address memset(&mesh->pdata, 0, sizeof(mesh->pdata)); } else { + Set names_to_skip; if (!BLO_write_is_undo(writer)) { BKE_mesh_legacy_convert_hide_layers_to_flags(mesh); + /* When converting to the old mesh format, don't save redunant attributes. */ + names_to_skip.add_multiple_new({".hide_vert", ".hide_edge", ".hide_poly"}); } - CustomData_blend_write_prepare(mesh->vdata, vert_layers, {".hide_vert"}); - CustomData_blend_write_prepare(mesh->edata, edge_layers, {".hide_edge"}); - CustomData_blend_write_prepare(mesh->ldata, loop_layers); - CustomData_blend_write_prepare(mesh->pdata, poly_layers, {".hide_poly"}); + CustomData_blend_write_prepare(mesh->vdata, vert_layers, names_to_skip); + CustomData_blend_write_prepare(mesh->edata, edge_layers, names_to_skip); + CustomData_blend_write_prepare(mesh->ldata, loop_layers, names_to_skip); + CustomData_blend_write_prepare(mesh->pdata, poly_layers, names_to_skip); } BLO_write_id_struct(writer, Mesh, id_address, &mesh->id); -- cgit v1.2.3 From a3e1a9e2aace26a71c2698cd96ce4086db25e94d Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 26 Aug 2022 12:45:20 +1000 Subject: Cleanup: spelling in comments, format --- source/blender/blenkernel/intern/mesh.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender/blenkernel/intern/mesh.cc') diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 7f2c09f049b..272dd922caa 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -249,7 +249,7 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address Set names_to_skip; if (!BLO_write_is_undo(writer)) { BKE_mesh_legacy_convert_hide_layers_to_flags(mesh); - /* When converting to the old mesh format, don't save redunant attributes. */ + /* When converting to the old mesh format, don't save redundant attributes. */ names_to_skip.add_multiple_new({".hide_vert", ".hide_edge", ".hide_poly"}); } -- cgit v1.2.3 From 3306b4a86bb8dcb0a1640fc73c355e5fff9073a7 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Tue, 30 Aug 2022 10:41:26 -0500 Subject: Fix T99253: Missing face center dots with deform modifier cage option Before 8c25889bb67db4c, subsurf face center tags were stored in each vertex, so they were always copied to duplicate meshes. Now they are stored in runtime data though, so they need to be copied explicitly. The function name "reset_on_copy" is a bit awkward here, so the tags are copied by the caller. --- source/blender/blenkernel/intern/mesh.cc | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'source/blender/blenkernel/intern/mesh.cc') diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index cf05dc0404e..afd8e49f884 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -96,6 +96,10 @@ static void mesh_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int const Mesh *mesh_src = (const Mesh *)id_src; BKE_mesh_runtime_reset_on_copy(mesh_dst, flag); + /* Copy face dot tags, since meshes may be duplicated after a subsurf modifier + * or node, but we still need to be able to draw face center vertices. */ + mesh_dst->runtime.subsurf_face_dot_tags = static_cast( + MEM_dupallocN(mesh_src->runtime.subsurf_face_dot_tags)); if ((mesh_src->id.tag & LIB_TAG_NO_MAIN) == 0) { /* This is a direct copy of a main mesh, so for now it has the same topology. */ mesh_dst->runtime.deformed_only = true; -- cgit v1.2.3 From 25237d2625078c6d14d744f288776299efd3c7c8 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Tue, 30 Aug 2022 14:54:53 -0500 Subject: Attributes: Improve custom data initialization options When allocating new `CustomData` layers, often we do redundant initialization of arrays. For example, it's common that values are allocated, set to their default value, and then set to some other value. This is wasteful, and it negates the benefits of optimizations to the allocator like D15082. There are two reasons for this. The first is array-of-structs storage that makes it annoying to initialize values manually, and the second is confusing options in the Custom Data API. This patch addresses the latter. The `CustomData` "alloc type" options are rearranged. Now, besides the options that use existing layers, there are two remaining: * `CD_SET_DEFAULT` sets the default value. * Usually zeroes, but for colors this is white (how it was before). * Should be used when you add the layer but don't set all values. * `CD_CONSTRUCT` refers to the "default construct" C++ term. * Only necessary or defined for non-trivial types like vertex groups. * Doesn't do anything for trivial types like `int` or `float3`. * Should be used every other time, when all values will be set. The attribute API's `AttributeInit` types are updated as well. To update code, replace `CD_CALLOC` with `CD_SET_DEFAULT` and `CD_DEFAULT` with `CD_CONSTRUCT`. This doesn't cause any functional changes yet. Follow-up commits will change to avoid initializing new layers where the correctness is clear. Differential Revision: https://developer.blender.org/D15617 --- source/blender/blenkernel/intern/mesh.cc | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'source/blender/blenkernel/intern/mesh.cc') diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 0c109e6ef04..0a5eddfd319 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -822,7 +822,7 @@ void BKE_mesh_ensure_skin_customdata(Mesh *me) else { if (!CustomData_has_layer(&me->vdata, CD_MVERT_SKIN)) { vs = (MVertSkin *)CustomData_add_layer( - &me->vdata, CD_MVERT_SKIN, CD_DEFAULT, nullptr, me->totvert); + &me->vdata, CD_MVERT_SKIN, CD_SET_DEFAULT, nullptr, me->totvert); /* Mark an arbitrary vertex as root */ if (vs) { @@ -844,7 +844,7 @@ bool BKE_mesh_ensure_facemap_customdata(struct Mesh *me) } else { if (!CustomData_has_layer(&me->pdata, CD_FACEMAP)) { - CustomData_add_layer(&me->pdata, CD_FACEMAP, CD_DEFAULT, nullptr, me->totpoly); + CustomData_add_layer(&me->pdata, CD_FACEMAP, CD_SET_DEFAULT, nullptr, me->totpoly); changed = true; } } @@ -987,20 +987,20 @@ Mesh *BKE_mesh_add(Main *bmain, const char *name) static void mesh_ensure_cdlayers_primary(Mesh *mesh, bool do_tessface) { if (!CustomData_get_layer(&mesh->vdata, CD_MVERT)) { - CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CALLOC, nullptr, mesh->totvert); + CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_SET_DEFAULT, nullptr, mesh->totvert); } if (!CustomData_get_layer(&mesh->edata, CD_MEDGE)) { - CustomData_add_layer(&mesh->edata, CD_MEDGE, CD_CALLOC, nullptr, mesh->totedge); + CustomData_add_layer(&mesh->edata, CD_MEDGE, CD_SET_DEFAULT, nullptr, mesh->totedge); } if (!CustomData_get_layer(&mesh->ldata, CD_MLOOP)) { - CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CALLOC, nullptr, mesh->totloop); + CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_SET_DEFAULT, nullptr, mesh->totloop); } if (!CustomData_get_layer(&mesh->pdata, CD_MPOLY)) { - CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CALLOC, nullptr, mesh->totpoly); + CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_SET_DEFAULT, nullptr, mesh->totpoly); } if (do_tessface && !CustomData_get_layer(&mesh->fdata, CD_MFACE)) { - CustomData_add_layer(&mesh->fdata, CD_MFACE, CD_CALLOC, nullptr, mesh->totface); + CustomData_add_layer(&mesh->fdata, CD_MFACE, CD_SET_DEFAULT, nullptr, mesh->totface); } } @@ -1097,12 +1097,12 @@ Mesh *BKE_mesh_new_nomain_from_template_ex(const Mesh *me_src, me_dst->cd_flag = me_src->cd_flag; BKE_mesh_copy_parameters_for_eval(me_dst, me_src); - CustomData_copy(&me_src->vdata, &me_dst->vdata, mask.vmask, CD_CALLOC, verts_len); - CustomData_copy(&me_src->edata, &me_dst->edata, mask.emask, CD_CALLOC, edges_len); - CustomData_copy(&me_src->ldata, &me_dst->ldata, mask.lmask, CD_CALLOC, loops_len); - CustomData_copy(&me_src->pdata, &me_dst->pdata, mask.pmask, CD_CALLOC, polys_len); + CustomData_copy(&me_src->vdata, &me_dst->vdata, mask.vmask, CD_SET_DEFAULT, verts_len); + CustomData_copy(&me_src->edata, &me_dst->edata, mask.emask, CD_SET_DEFAULT, edges_len); + CustomData_copy(&me_src->ldata, &me_dst->ldata, mask.lmask, CD_SET_DEFAULT, loops_len); + CustomData_copy(&me_src->pdata, &me_dst->pdata, mask.pmask, CD_SET_DEFAULT, polys_len); if (do_tessface) { - CustomData_copy(&me_src->fdata, &me_dst->fdata, mask.fmask, CD_CALLOC, tessface_len); + CustomData_copy(&me_src->fdata, &me_dst->fdata, mask.fmask, CD_SET_DEFAULT, tessface_len); } else { mesh_tessface_clear_intern(me_dst, false); @@ -1203,7 +1203,7 @@ static void ensure_orig_index_layer(CustomData &data, const int size) if (CustomData_has_layer(&data, CD_ORIGINDEX)) { return; } - int *indices = (int *)CustomData_add_layer(&data, CD_ORIGINDEX, CD_DEFAULT, nullptr, size); + int *indices = (int *)CustomData_add_layer(&data, CD_ORIGINDEX, CD_SET_DEFAULT, nullptr, size); range_vn_i(indices, size, 0); } @@ -1882,7 +1882,7 @@ static float (*ensure_corner_normal_layer(Mesh &mesh))[3] } else { r_loopnors = (float(*)[3])CustomData_add_layer( - &mesh.ldata, CD_NORMAL, CD_CALLOC, nullptr, mesh.totloop); + &mesh.ldata, CD_NORMAL, CD_SET_DEFAULT, nullptr, mesh.totloop); CustomData_set_layer_flag(&mesh.ldata, CD_NORMAL, CD_FLAG_TEMPORARY); } return r_loopnors; -- cgit v1.2.3 From f1c0249f34c4171ec311b5b9882e36fed5889259 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Wed, 31 Aug 2022 09:09:01 -0500 Subject: Mesh: Move material indices to a generic attribute This patch moves material indices from the mesh `MPoly` struct to a generic integer attribute. The builtin material index was already exposed in geometry nodes, but this makes it a "proper" attribute accessible with Python and visible in the "Attributes" panel. The goals of the refactor are code simplification and memory and performance improvements, mainly because the attribute doesn't have to be stored and processed if there are no materials. However, until 4.0, material indices will still be read and written in the old format, meaning there may be a temporary increase in memory usage. Further notes: * Completely removing the `MPoly.mat_nr` after 4.0 may require changes to DNA or introducing a new `MPoly` type. * Geometry nodes regression tests didn't look at material indices, so the change reveals a bug in the realize instances node that I fixed. * Access to material indices from the RNA `MeshPolygon` type is slower with this patch. The `material_index` attribute can be used instead. * Cycles is changed to read from the attribute instead. * BMesh isn't changed in this patch. Theoretically it could be though, to save 2 bytes per face when less than two materials are used. * Eventually we could use a 16 bit integer attribute type instead. Ref T95967 Differential Revision: https://developer.blender.org/D15675 --- source/blender/blenkernel/intern/mesh.cc | 95 ++++++++++++++++++-------------- 1 file changed, 53 insertions(+), 42 deletions(-) (limited to 'source/blender/blenkernel/intern/mesh.cc') diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 0a5eddfd319..b44a956eec4 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -33,6 +33,7 @@ #include "BLI_task.hh" #include "BLI_utildefines.h" #include "BLI_vector.hh" +#include "BLI_virtual_array.hh" #include "BLT_translation.h" @@ -253,6 +254,7 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address Set names_to_skip; if (!BLO_write_is_undo(writer)) { BKE_mesh_legacy_convert_hide_layers_to_flags(mesh); + BKE_mesh_legacy_convert_material_indices_to_mpoly(mesh); /* When converting to the old mesh format, don't save redundant attributes. */ names_to_skip.add_multiple_new({".hide_vert", ".hide_edge", ".hide_poly"}); } @@ -341,6 +343,7 @@ static void mesh_blend_read_data(BlendDataReader *reader, ID *id) if (!BLO_read_data_is_undo(reader)) { BKE_mesh_legacy_convert_flags_to_hide_layers(mesh); + BKE_mesh_legacy_convert_mpoly_to_material_indices(mesh); } /* We don't expect to load normals from files, since they are derived data. */ @@ -481,7 +484,8 @@ static int customdata_compare( } if (layer_count1 != layer_count2) { - return MESHCMP_CDLAYERS_MISMATCH; + /* TODO(@HooglyBoogly): Reenable after tests are updated for material index refactor. */ + // return MESHCMP_CDLAYERS_MISMATCH; } l1 = c1->layers; @@ -1416,61 +1420,57 @@ void BKE_mesh_assign_object(Main *bmain, Object *ob, Mesh *me) void BKE_mesh_material_index_remove(Mesh *me, short index) { - MPoly *mp; - MFace *mf; - int i; - - for (mp = me->mpoly, i = 0; i < me->totpoly; i++, mp++) { - if (mp->mat_nr && mp->mat_nr >= index) { - mp->mat_nr--; - } + using namespace blender; + using namespace blender::bke; + MutableAttributeAccessor attributes = mesh_attributes_for_write(*me); + AttributeWriter material_indices = attributes.lookup_for_write("material_index"); + if (!material_indices) { + return; } - - for (mf = me->mface, i = 0; i < me->totface; i++, mf++) { - if (mf->mat_nr && mf->mat_nr >= index) { - mf->mat_nr--; + if (material_indices.domain != ATTR_DOMAIN_FACE) { + BLI_assert_unreachable(); + return; + } + MutableVArraySpan indices_span(material_indices.varray); + for (const int i : indices_span.index_range()) { + if (indices_span[i] > 0 && indices_span[i] > index) { + indices_span[i]--; } } + indices_span.save(); + material_indices.finish(); + + BKE_mesh_tessface_clear(me); } bool BKE_mesh_material_index_used(Mesh *me, short index) { - MPoly *mp; - MFace *mf; - int i; - - for (mp = me->mpoly, i = 0; i < me->totpoly; i++, mp++) { - if (mp->mat_nr == index) { - return true; - } - } - - for (mf = me->mface, i = 0; i < me->totface; i++, mf++) { - if (mf->mat_nr == index) { - return true; - } + using namespace blender; + using namespace blender::bke; + const AttributeAccessor attributes = mesh_attributes(*me); + const VArray material_indices = attributes.lookup_or_default( + "material_index", ATTR_DOMAIN_FACE, 0); + if (material_indices.is_single()) { + return material_indices.get_internal_single() == index; } - - return false; + const VArraySpan indices_span(material_indices); + return indices_span.contains(index); } void BKE_mesh_material_index_clear(Mesh *me) { - MPoly *mp; - MFace *mf; - int i; - - for (mp = me->mpoly, i = 0; i < me->totpoly; i++, mp++) { - mp->mat_nr = 0; - } + using namespace blender; + using namespace blender::bke; + MutableAttributeAccessor attributes = mesh_attributes_for_write(*me); + attributes.remove("material_index"); - for (mf = me->mface, i = 0; i < me->totface; i++, mf++) { - mf->mat_nr = 0; - } + BKE_mesh_tessface_clear(me); } void BKE_mesh_material_remap(Mesh *me, const uint *remap, uint remap_len) { + using namespace blender; + using namespace blender::bke; const short remap_len_short = (short)remap_len; #define MAT_NR_REMAP(n) \ @@ -1490,10 +1490,21 @@ void BKE_mesh_material_remap(Mesh *me, const uint *remap, uint remap_len) } } else { - int i; - for (i = 0; i < me->totpoly; i++) { - MAT_NR_REMAP(me->mpoly[i].mat_nr); + MutableAttributeAccessor attributes = mesh_attributes_for_write(*me); + AttributeWriter material_indices = attributes.lookup_for_write("material_index"); + if (!material_indices) { + return; + } + if (material_indices.domain != ATTR_DOMAIN_FACE) { + BLI_assert_unreachable(); + return; + } + MutableVArraySpan indices_span(material_indices.varray); + for (const int i : indices_span.index_range()) { + MAT_NR_REMAP(indices_span[i]); } + indices_span.save(); + material_indices.finish(); } #undef MAT_NR_REMAP -- cgit v1.2.3 From 05952aa94d33eeb504fa63618ba35c2bcc8bd19b Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Mon, 5 Sep 2022 11:56:34 -0500 Subject: Mesh: Remove redundant custom data pointers For copy-on-write, we want to share attribute arrays between meshes where possible. Mutable pointers like `Mesh.mvert` make that difficult by making ownership vague. They also make code more complex by adding redundancy. The simplest solution is just removing them and retrieving layers from `CustomData` as needed. Similar changes have already been applied to curves and point clouds (e9f82d3dc7ee, 410a6efb747f). Removing use of the pointers generally makes code more obvious and more reusable. Mesh data is now accessed with a C++ API (`Mesh::edges()` or `Mesh::edges_for_write()`), and a C API (`BKE_mesh_edges(mesh)`). The CoW changes this commit makes possible are described in T95845 and T95842, and started in D14139 and D14140. The change also simplifies the ongoing mesh struct-of-array refactors from T95965. **RNA/Python Access Performance** Theoretically, accessing mesh elements with the RNA API may become slower, since the layer needs to be found on every random access. However, overhead is already high enough that this doesn't make a noticible differenc, and performance is actually improved in some cases. Random access can be up to 10% faster, but other situations might be a bit slower. Generally using `foreach_get/set` are the best way to improve performance. See the differential revision for more discussion about Python performance. Cycles has been updated to use raw pointers and the internal Blender mesh types, mostly because there is no sense in having this overhead when it's already compiled with Blender. In my tests this roughly halves the Cycles mesh creation time (0.19s to 0.10s for a 1 million face grid). Differential Revision: https://developer.blender.org/D15488 --- source/blender/blenkernel/intern/mesh.cc | 289 +++++++++++-------------------- 1 file changed, 97 insertions(+), 192 deletions(-) (limited to 'source/blender/blenkernel/intern/mesh.cc') diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index b44a956eec4..c0379c50de4 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -66,6 +66,7 @@ using blender::float3; using blender::MutableSpan; +using blender::Span; using blender::VArray; using blender::Vector; @@ -146,8 +147,6 @@ static void mesh_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int mesh_tessface_clear_intern(mesh_dst, false); } - BKE_mesh_update_customdata_pointers(mesh_dst, do_tessface); - mesh_dst->cd_flag = mesh_src->cd_flag; mesh_dst->edit_mesh = nullptr; @@ -234,29 +233,32 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address /* Do not store actual geometry data in case this is a library override ID. */ if (ID_IS_OVERRIDE_LIBRARY(mesh) && !is_undo) { - mesh->mvert = nullptr; mesh->totvert = 0; memset(&mesh->vdata, 0, sizeof(mesh->vdata)); - mesh->medge = nullptr; mesh->totedge = 0; memset(&mesh->edata, 0, sizeof(mesh->edata)); - mesh->mloop = nullptr; mesh->totloop = 0; memset(&mesh->ldata, 0, sizeof(mesh->ldata)); - mesh->mpoly = nullptr; mesh->totpoly = 0; memset(&mesh->pdata, 0, sizeof(mesh->pdata)); } else { Set names_to_skip; if (!BLO_write_is_undo(writer)) { + BKE_mesh_legacy_convert_hide_layers_to_flags(mesh); BKE_mesh_legacy_convert_material_indices_to_mpoly(mesh); /* When converting to the old mesh format, don't save redundant attributes. */ names_to_skip.add_multiple_new({".hide_vert", ".hide_edge", ".hide_poly"}); + + /* Set deprecated mesh data pointers for forward compatibility. */ + mesh->mvert = const_cast(mesh->vertices().data()); + mesh->medge = const_cast(mesh->edges().data()); + mesh->mpoly = const_cast(mesh->polygons().data()); + mesh->mloop = const_cast(mesh->loops().data()); } CustomData_blend_write_prepare(mesh->vdata, vert_layers, names_to_skip); @@ -295,17 +297,16 @@ static void mesh_blend_read_data(BlendDataReader *reader, ID *id) Mesh *mesh = (Mesh *)id; BLO_read_pointer_array(reader, (void **)&mesh->mat); + /* Deprecated pointers to custom data layers are read here for backward compatibility + * with files where these were owning pointers rather than a view into custom data. */ BLO_read_data_address(reader, &mesh->mvert); BLO_read_data_address(reader, &mesh->medge); BLO_read_data_address(reader, &mesh->mface); - BLO_read_data_address(reader, &mesh->mloop); - BLO_read_data_address(reader, &mesh->mpoly); - BLO_read_data_address(reader, &mesh->tface); BLO_read_data_address(reader, &mesh->mtface); - BLO_read_data_address(reader, &mesh->mcol); BLO_read_data_address(reader, &mesh->dvert); - BLO_read_data_address(reader, &mesh->mloopcol); - BLO_read_data_address(reader, &mesh->mloopuv); + BLO_read_data_address(reader, &mesh->tface); + BLO_read_data_address(reader, &mesh->mcol); + BLO_read_data_address(reader, &mesh->mselect); /* animdata */ @@ -468,6 +469,8 @@ static int customdata_compare( CD_MASK_MLOOPUV | CD_MASK_PROP_BYTE_COLOR | CD_MASK_MDEFORMVERT; const uint64_t cd_mask_all_attr = CD_MASK_PROP_ALL | cd_mask_non_generic; + const Span loops_1 = m1->loops(); + const Span loops_2 = m2->loops(); for (int i = 0; i < c1->totlayer; i++) { l1 = &c1->layers[i]; @@ -543,15 +546,14 @@ static int customdata_compare( int ptot = m1->totpoly; for (j = 0; j < ptot; j++, p1++, p2++) { - MLoop *lp1, *lp2; int k; if (p1->totloop != p2->totloop) { return MESHCMP_POLYMISMATCH; } - lp1 = m1->mloop + p1->loopstart; - lp2 = m2->mloop + p2->loopstart; + const MLoop *lp1 = &loops_1[p1->loopstart]; + const MLoop *lp2 = &loops_2[p2->loopstart]; for (k = 0; k < p1->totloop; k++, lp1++, lp2++) { if (lp1->v != lp2->v) { @@ -762,47 +764,6 @@ const char *BKE_mesh_cmp(Mesh *me1, Mesh *me2, float thresh) return nullptr; } -static void mesh_ensure_tessellation_customdata(Mesh *me) -{ - if (UNLIKELY((me->totface != 0) && (me->totpoly == 0))) { - /* Pass, otherwise this function clears 'mface' before - * versioning 'mface -> mpoly' code kicks in T30583. - * - * Callers could also check but safer to do here - campbell */ - } - else { - const int tottex_original = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV); - const int totcol_original = CustomData_number_of_layers(&me->ldata, CD_PROP_BYTE_COLOR); - - const int tottex_tessface = CustomData_number_of_layers(&me->fdata, CD_MTFACE); - const int totcol_tessface = CustomData_number_of_layers(&me->fdata, CD_MCOL); - - if (tottex_tessface != tottex_original || totcol_tessface != totcol_original) { - BKE_mesh_tessface_clear(me); - - BKE_mesh_add_mface_layers(&me->fdata, &me->ldata, me->totface); - - /* TODO: add some `--debug-mesh` option. */ - if (G.debug & G_DEBUG) { - /* NOTE(@campbellbarton): this warning may be un-called for if we are initializing the mesh - * for the first time from #BMesh, rather than giving a warning about this we could be - * smarter and check if there was any data to begin with, for now just print the warning - * with some info to help troubleshoot what's going on. */ - printf( - "%s: warning! Tessellation uvs or vcol data got out of sync, " - "had to reset!\n CD_MTFACE: %d != CD_MLOOPUV: %d || CD_MCOL: %d != " - "CD_PROP_BYTE_COLOR: " - "%d\n", - __func__, - tottex_tessface, - tottex_original, - totcol_tessface, - totcol_original); - } - } - } -} - void BKE_mesh_ensure_skin_customdata(Mesh *me) { BMesh *bm = me->edit_mesh ? me->edit_mesh->bm : nullptr; @@ -874,43 +835,6 @@ bool BKE_mesh_clear_facemap_customdata(struct Mesh *me) return changed; } -/** - * This ensures grouped custom-data (e.g. #CD_MLOOPUV and #CD_MTFACE, or - * #CD_PROP_BYTE_COLOR and #CD_MCOL) have the same relative active/render/clone/mask indices. - * - * NOTE(@campbellbarton): that for undo mesh data we want to skip 'ensure_tess_cd' call since - * we don't want to store memory for #MFace data when its only used for older - * versions of the mesh. - */ -static void mesh_update_linked_customdata(Mesh *me, const bool do_ensure_tess_cd) -{ - if (do_ensure_tess_cd) { - mesh_ensure_tessellation_customdata(me); - } - - CustomData_bmesh_update_active_layers(&me->fdata, &me->ldata); -} - -void BKE_mesh_update_customdata_pointers(Mesh *me, const bool do_ensure_tess_cd) -{ - mesh_update_linked_customdata(me, do_ensure_tess_cd); - - me->mvert = (MVert *)CustomData_get_layer(&me->vdata, CD_MVERT); - me->dvert = (MDeformVert *)CustomData_get_layer(&me->vdata, CD_MDEFORMVERT); - - me->medge = (MEdge *)CustomData_get_layer(&me->edata, CD_MEDGE); - - me->mface = (MFace *)CustomData_get_layer(&me->fdata, CD_MFACE); - me->mcol = (MCol *)CustomData_get_layer(&me->fdata, CD_MCOL); - me->mtface = (MTFace *)CustomData_get_layer(&me->fdata, CD_MTFACE); - - me->mpoly = (MPoly *)CustomData_get_layer(&me->pdata, CD_MPOLY); - me->mloop = (MLoop *)CustomData_get_layer(&me->ldata, CD_MLOOP); - - me->mloopcol = (MLoopCol *)CustomData_get_layer(&me->ldata, CD_PROP_BYTE_COLOR); - me->mloopuv = (MLoopUV *)CustomData_get_layer(&me->ldata, CD_MLOOPUV); -} - bool BKE_mesh_has_custom_loop_normals(Mesh *me) { if (me->edit_mesh) { @@ -954,8 +878,6 @@ static void mesh_clear_geometry(Mesh *mesh) mesh->totpoly = 0; mesh->act_face = -1; mesh->totselect = 0; - - BKE_mesh_update_customdata_pointers(mesh, false); } void BKE_mesh_clear_geometry(Mesh *mesh) @@ -974,9 +896,6 @@ static void mesh_tessface_clear_intern(Mesh *mesh, int free_customdata) CustomData_reset(&mesh->fdata); } - mesh->mface = nullptr; - mesh->mtface = nullptr; - mesh->mcol = nullptr; mesh->totface = 0; } @@ -1029,7 +948,6 @@ Mesh *BKE_mesh_new_nomain( mesh->totpoly = polys_len; mesh_ensure_cdlayers_primary(mesh, true); - BKE_mesh_update_customdata_pointers(mesh, false); return mesh; } @@ -1115,7 +1033,6 @@ Mesh *BKE_mesh_new_nomain_from_template_ex(const Mesh *me_src, /* The destination mesh should at least have valid primary CD layers, * even in cases where the source mesh does not. */ mesh_ensure_cdlayers_primary(me_dst, do_tessface); - BKE_mesh_update_customdata_pointers(me_dst, false); /* Expect that normals aren't copied at all, since the destination mesh is new. */ BLI_assert(BKE_mesh_vertex_normals_are_dirty(me_dst)); @@ -1338,11 +1255,12 @@ float (*BKE_mesh_orco_verts_get(Object *ob))[3] /* Get appropriate vertex coordinates */ float(*vcos)[3] = (float(*)[3])MEM_calloc_arrayN(me->totvert, sizeof(*vcos), "orco mesh"); - MVert *mvert = tme->mvert; + const Span verts = tme->vertices(); + int totvert = min_ii(tme->totvert, me->totvert); - for (int a = 0; a < totvert; a++, mvert++) { - copy_v3_v3(vcos[a], mvert->co); + for (int a = 0; a < totvert; a++) { + copy_v3_v3(vcos[a], verts[a].co); } return vcos; @@ -1512,14 +1430,15 @@ void BKE_mesh_material_remap(Mesh *me, const uint *remap, uint remap_len) void BKE_mesh_smooth_flag_set(Mesh *me, const bool use_smooth) { + MutableSpan polys = me->polygons_for_write(); if (use_smooth) { - for (int i = 0; i < me->totpoly; i++) { - me->mpoly[i].flag |= ME_SMOOTH; + for (MPoly &poly : polys) { + poly.flag |= ME_SMOOTH; } } else { - for (int i = 0; i < me->totpoly; i++) { - me->mpoly[i].flag &= ~ME_SMOOTH; + for (MPoly &poly : polys) { + poly.flag &= ~ME_SMOOTH; } } } @@ -1575,9 +1494,12 @@ int BKE_mesh_edge_other_vert(const MEdge *e, int v) void BKE_mesh_looptri_get_real_edges(const Mesh *mesh, const MLoopTri *looptri, int r_edges[3]) { + const Span edges = mesh->edges(); + const Span loops = mesh->loops(); + for (int i = 2, i_next = 0; i_next < 3; i = i_next++) { - const MLoop *l1 = &mesh->mloop[looptri->tri[i]], *l2 = &mesh->mloop[looptri->tri[i_next]]; - const MEdge *e = &mesh->medge[l1->e]; + const MLoop *l1 = &loops[looptri->tri[i]], *l2 = &loops[looptri->tri[i_next]]; + const MEdge *e = &edges[l1->e]; bool is_real = (l1->v == e->v1 && l2->v == e->v2) || (l1->v == e->v2 && l2->v == e->v1); @@ -1596,15 +1518,16 @@ bool BKE_mesh_minmax(const Mesh *me, float r_min[3], float r_max[3]) float3 min; float3 max; }; + const Span verts = me->vertices(); const Result minmax = threading::parallel_reduce( - IndexRange(me->totvert), + verts.index_range(), 1024, Result{float3(FLT_MAX), float3(-FLT_MAX)}, - [&](IndexRange range, const Result &init) { + [verts](IndexRange range, const Result &init) { Result result = init; for (const int i : range) { - math::min_max(float3(me->mvert[i].co), result.min, result.max); + math::min_max(float3(verts[i].co), result.min, result.max); } return result; }, @@ -1620,22 +1543,16 @@ bool BKE_mesh_minmax(const Mesh *me, float r_min[3], float r_max[3]) void BKE_mesh_transform(Mesh *me, const float mat[4][4], bool do_keys) { - int i; - MVert *mvert = (MVert *)CustomData_duplicate_referenced_layer(&me->vdata, CD_MVERT, me->totvert); - float(*lnors)[3] = (float(*)[3])CustomData_duplicate_referenced_layer( - &me->ldata, CD_NORMAL, me->totloop); - - /* If the referenced layer has been re-allocated need to update pointers stored in the mesh. */ - BKE_mesh_update_customdata_pointers(me, false); + MutableSpan verts = me->vertices_for_write(); - for (i = 0; i < me->totvert; i++, mvert++) { - mul_m4_v3(mat, mvert->co); + for (MVert &vert : verts) { + mul_m4_v3(mat, vert.co); } if (do_keys && me->key) { LISTBASE_FOREACH (KeyBlock *, kb, &me->key->block) { float *fp = (float *)kb->data; - for (i = kb->totelem; i--; fp += 3) { + for (int i = kb->totelem; i--; fp += 3) { mul_m4_v3(mat, fp); } } @@ -1644,12 +1561,14 @@ void BKE_mesh_transform(Mesh *me, const float mat[4][4], bool do_keys) /* don't update normals, caller can do this explicitly. * We do update loop normals though, those may not be auto-generated * (see e.g. STL import script)! */ + float(*lnors)[3] = (float(*)[3])CustomData_duplicate_referenced_layer( + &me->ldata, CD_NORMAL, me->totloop); if (lnors) { float m3[3][3]; copy_m3_m4(m3, mat); normalize_m3(m3); - for (i = 0; i < me->totloop; i++, lnors++) { + for (int i = 0; i < me->totloop; i++, lnors++) { mul_m3_v3(m3, *lnors); } } @@ -1658,15 +1577,12 @@ void BKE_mesh_transform(Mesh *me, const float mat[4][4], bool do_keys) void BKE_mesh_translate(Mesh *me, const float offset[3], const bool do_keys) { - CustomData_duplicate_referenced_layer(&me->vdata, CD_MVERT, me->totvert); - /* If the referenced layer has been re-allocated need to update pointers stored in the mesh. */ - BKE_mesh_update_customdata_pointers(me, false); - - int i = me->totvert; - for (MVert *mvert = me->mvert; i--; mvert++) { - add_v3_v3(mvert->co, offset); + MutableSpan verts = me->vertices_for_write(); + for (MVert &vert : verts) { + add_v3_v3(vert.co, offset); } + int i; if (do_keys && me->key) { LISTBASE_FOREACH (KeyBlock *, kb, &me->key->block) { float *fp = (float *)kb->data; @@ -1689,25 +1605,24 @@ void BKE_mesh_do_versions_cd_flag_init(Mesh *mesh) return; } - MVert *mv; - MEdge *med; - int i; + const Span verts = mesh->vertices(); + const Span edges = mesh->edges(); - for (mv = mesh->mvert, i = 0; i < mesh->totvert; mv++, i++) { - if (mv->bweight != 0) { + for (const MVert &vert : verts) { + if (vert.bweight != 0) { mesh->cd_flag |= ME_CDFLAG_VERT_BWEIGHT; break; } } - for (med = mesh->medge, i = 0; i < mesh->totedge; med++, i++) { - if (med->bweight != 0) { + for (const MEdge &edge : edges) { + if (edge.bweight != 0) { mesh->cd_flag |= ME_CDFLAG_EDGE_BWEIGHT; if (mesh->cd_flag & ME_CDFLAG_EDGE_CREASE) { break; } } - if (med->crease != 0) { + if (edge.crease != 0) { mesh->cd_flag |= ME_CDFLAG_EDGE_CREASE; if (mesh->cd_flag & ME_CDFLAG_EDGE_BWEIGHT) { break; @@ -1733,6 +1648,9 @@ void BKE_mesh_mselect_validate(Mesh *me) if (me->totselect == 0) { return; } + const Span verts = me->vertices(); + const Span edges = me->edges(); + const Span polys = me->polygons(); mselect_src = me->mselect; mselect_dst = (MSelect *)MEM_malloc_arrayN( @@ -1742,21 +1660,21 @@ void BKE_mesh_mselect_validate(Mesh *me) int index = mselect_src[i_src].index; switch (mselect_src[i_src].type) { case ME_VSEL: { - if (me->mvert[index].flag & SELECT) { + if (verts[index].flag & SELECT) { mselect_dst[i_dst] = mselect_src[i_src]; i_dst++; } break; } case ME_ESEL: { - if (me->medge[index].flag & SELECT) { + if (edges[index].flag & SELECT) { mselect_dst[i_dst] = mselect_src[i_src]; i_dst++; } break; } case ME_FSEL: { - if (me->mpoly[index].flag & SELECT) { + if (polys[index].flag & SELECT) { mselect_dst[i_dst] = mselect_src[i_src]; i_dst++; } @@ -1842,10 +1760,10 @@ void BKE_mesh_count_selected_items(const Mesh *mesh, int r_count[3]) void BKE_mesh_vert_coords_get(const Mesh *mesh, float (*vert_coords)[3]) { - const MVert *mv = mesh->mvert; - for (int i = 0; i < mesh->totvert; i++, mv++) { - copy_v3_v3(vert_coords[i], mv->co); - } + blender::bke::AttributeAccessor attributes = blender::bke::mesh_attributes(*mesh); + VArray positions = attributes.lookup_or_default( + "position", ATTR_DOMAIN_POINT, float3(0)); + positions.materialize({(float3 *)vert_coords, mesh->totvert}); } float (*BKE_mesh_vert_coords_alloc(const Mesh *mesh, int *r_vert_len))[3] @@ -1860,12 +1778,9 @@ float (*BKE_mesh_vert_coords_alloc(const Mesh *mesh, int *r_vert_len))[3] void BKE_mesh_vert_coords_apply(Mesh *mesh, const float (*vert_coords)[3]) { - /* This will just return the pointer if it wasn't a referenced layer. */ - MVert *mv = (MVert *)CustomData_duplicate_referenced_layer( - &mesh->vdata, CD_MVERT, mesh->totvert); - mesh->mvert = mv; - for (int i = 0; i < mesh->totvert; i++, mv++) { - copy_v3_v3(mv->co, vert_coords[i]); + MutableSpan verts = mesh->vertices_for_write(); + for (const int i : verts.index_range()) { + copy_v3_v3(verts[i].co, vert_coords[i]); } BKE_mesh_tag_coords_changed(mesh); } @@ -1874,12 +1789,9 @@ void BKE_mesh_vert_coords_apply_with_mat4(Mesh *mesh, const float (*vert_coords)[3], const float mat[4][4]) { - /* This will just return the pointer if it wasn't a referenced layer. */ - MVert *mv = (MVert *)CustomData_duplicate_referenced_layer( - &mesh->vdata, CD_MVERT, mesh->totvert); - mesh->mvert = mv; - for (int i = 0; i < mesh->totvert; i++, mv++) { - mul_v3_m4v3(mv->co, mat, vert_coords[i]); + MutableSpan verts = mesh->vertices_for_write(); + for (const int i : verts.index_range()) { + mul_v3_m4v3(verts[i].co, mat, vert_coords[i]); } BKE_mesh_tag_coords_changed(mesh); } @@ -1915,17 +1827,22 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, /* may be nullptr */ clnors = (short(*)[2])CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL); - BKE_mesh_normals_loop_split(mesh->mvert, + const Span verts = mesh->vertices(); + const Span edges = mesh->edges(); + const Span polys = mesh->polygons(); + const Span loops = mesh->loops(); + + BKE_mesh_normals_loop_split(verts.data(), BKE_mesh_vertex_normals_ensure(mesh), - mesh->totvert, - mesh->medge, - mesh->totedge, - mesh->mloop, + verts.size(), + edges.data(), + edges.size(), + loops.data(), r_corner_normals, - mesh->totloop, - mesh->mpoly, + loops.size(), + polys.data(), BKE_mesh_poly_normals_ensure(mesh), - mesh->totpoly, + polys.size(), use_split_normals, split_angle, r_lnors_spacearr, @@ -1971,14 +1888,14 @@ static int split_faces_prepare_new_verts(Mesh *mesh, const int loops_len = mesh->totloop; int verts_len = mesh->totvert; - MLoop *mloop = mesh->mloop; + MutableSpan loops = mesh->loops_for_write(); BKE_mesh_vertex_normals_ensure(mesh); float(*vert_normals)[3] = BKE_mesh_vertex_normals_for_write(mesh); BLI_bitmap *verts_used = BLI_BITMAP_NEW(verts_len, __func__); BLI_bitmap *done_loops = BLI_BITMAP_NEW(loops_len, __func__); - MLoop *ml = mloop; + MLoop *ml = loops.data(); MLoopNorSpace **lnor_space = lnors_spacearr->lspacearr; BLI_assert(lnors_spacearr->data_type == MLNOR_SPACEARR_LOOP_INDEX); @@ -2005,7 +1922,7 @@ static int split_faces_prepare_new_verts(Mesh *mesh, const int ml_fan_idx = POINTER_AS_INT(lnode->link); BLI_BITMAP_ENABLE(done_loops, ml_fan_idx); if (vert_used) { - mloop[ml_fan_idx].v = new_vert_idx; + loops[ml_fan_idx].v = new_vert_idx; } } } @@ -2040,23 +1957,23 @@ static int split_faces_prepare_new_verts(Mesh *mesh, /* Detect needed new edges, and update accordingly loops' edge indices. * WARNING! Leaves mesh in invalid state. */ -static int split_faces_prepare_new_edges(const Mesh *mesh, +static int split_faces_prepare_new_edges(Mesh *mesh, SplitFaceNewEdge **new_edges, MemArena *memarena) { const int num_polys = mesh->totpoly; int num_edges = mesh->totedge; - MEdge *medge = mesh->medge; - MLoop *mloop = mesh->mloop; - const MPoly *mpoly = mesh->mpoly; + MutableSpan edges = mesh->edges_for_write(); + MutableSpan loops = mesh->loops_for_write(); + const Span polys = mesh->polygons(); BLI_bitmap *edges_used = BLI_BITMAP_NEW(num_edges, __func__); EdgeHash *edges_hash = BLI_edgehash_new_ex(__func__, num_edges); - const MPoly *mp = mpoly; + const MPoly *mp = polys.data(); for (int poly_idx = 0; poly_idx < num_polys; poly_idx++, mp++) { - MLoop *ml_prev = &mloop[mp->loopstart + mp->totloop - 1]; - MLoop *ml = &mloop[mp->loopstart]; + MLoop *ml_prev = &loops[mp->loopstart + mp->totloop - 1]; + MLoop *ml = &loops[mp->loopstart]; for (int loop_idx = 0; loop_idx < mp->totloop; loop_idx++, ml++) { void **eval; if (!BLI_edgehash_ensure_p(edges_hash, ml_prev->v, ml->v, &eval)) { @@ -2080,8 +1997,8 @@ static int split_faces_prepare_new_edges(const Mesh *mesh, } else { /* We can re-use original edge. */ - medge[edge_idx].v1 = ml_prev->v; - medge[edge_idx].v2 = ml->v; + edges[edge_idx].v1 = ml_prev->v; + edges[edge_idx].v2 = ml->v; *eval = POINTER_FROM_INT(edge_idx); BLI_BITMAP_ENABLE(edges_used, edge_idx); } @@ -2107,7 +2024,6 @@ static void split_faces_split_new_verts(Mesh *mesh, const int num_new_verts) { const int verts_len = mesh->totvert - num_new_verts; - MVert *mvert = mesh->mvert; float(*vert_normals)[3] = BKE_mesh_vertex_normals_for_write(mesh); /* Normals were already calculated at the beginning of this operation, we rely on that to update @@ -2115,8 +2031,7 @@ static void split_faces_split_new_verts(Mesh *mesh, BLI_assert(!BKE_mesh_vertex_normals_are_dirty(mesh)); /* Remember new_verts is a single linklist, so its items are in reversed order... */ - MVert *new_mv = &mvert[mesh->totvert - 1]; - for (int i = mesh->totvert - 1; i >= verts_len; i--, new_mv--, new_verts = new_verts->next) { + for (int i = mesh->totvert - 1; i >= verts_len; i--, new_verts = new_verts->next) { BLI_assert(new_verts->new_index == i); BLI_assert(new_verts->new_index != new_verts->orig_index); CustomData_copy_data(&mesh->vdata, &mesh->vdata, new_verts->orig_index, i, 1); @@ -2132,10 +2047,10 @@ static void split_faces_split_new_edges(Mesh *mesh, const int num_new_edges) { const int num_edges = mesh->totedge - num_new_edges; - MEdge *medge = mesh->medge; + MutableSpan edges = mesh->edges_for_write(); /* Remember new_edges is a single linklist, so its items are in reversed order... */ - MEdge *new_med = &medge[mesh->totedge - 1]; + MEdge *new_med = &edges[mesh->totedge - 1]; for (int i = mesh->totedge - 1; i >= num_edges; i--, new_med--, new_edges = new_edges->next) { BLI_assert(new_edges->new_index == i); BLI_assert(new_edges->new_index != new_edges->orig_index); @@ -2163,14 +2078,6 @@ void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals) SplitFaceNewVert *new_verts = nullptr; SplitFaceNewEdge *new_edges = nullptr; - /* Ensure we own the layers, we need to do this before split_faces_prepare_new_verts as it will - * directly assign new indices to existing edges and loops. */ - CustomData_duplicate_referenced_layers(&mesh->vdata, mesh->totvert); - CustomData_duplicate_referenced_layers(&mesh->edata, mesh->totedge); - CustomData_duplicate_referenced_layers(&mesh->ldata, mesh->totloop); - /* Update pointers in case we duplicated referenced layers. */ - BKE_mesh_update_customdata_pointers(mesh, false); - /* Detect loop normal spaces (a.k.a. smooth fans) that will need a new vert. */ const int num_new_verts = split_faces_prepare_new_verts( mesh, &lnors_spacearr, &new_verts, memarena); @@ -2191,8 +2098,6 @@ void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals) mesh->totedge += num_new_edges; CustomData_realloc(&mesh->edata, mesh->totedge); } - /* Update pointers to a newly allocated memory. */ - BKE_mesh_update_customdata_pointers(mesh, false); /* Update normals manually to avoid recalculation after this operation. */ mesh->runtime.vert_normals = (float(*)[3])MEM_reallocN(mesh->runtime.vert_normals, -- cgit v1.2.3 From be038b844cb53bc228d3e98bfe09071560930cde Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Wed, 7 Sep 2022 00:06:31 -0500 Subject: Cleanup: Tweak naming for recently added mesh accessors Use `verts` instead of `vertices` and `polys` instead of `polygons` in the API added in 05952aa94d33eeb50. This aligns better with existing naming where the shorter names are much more common. --- source/blender/blenkernel/intern/mesh.cc | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'source/blender/blenkernel/intern/mesh.cc') diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index c0379c50de4..361eb9bcbbe 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -255,9 +255,9 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address names_to_skip.add_multiple_new({".hide_vert", ".hide_edge", ".hide_poly"}); /* Set deprecated mesh data pointers for forward compatibility. */ - mesh->mvert = const_cast(mesh->vertices().data()); + mesh->mvert = const_cast(mesh->verts().data()); mesh->medge = const_cast(mesh->edges().data()); - mesh->mpoly = const_cast(mesh->polygons().data()); + mesh->mpoly = const_cast(mesh->polys().data()); mesh->mloop = const_cast(mesh->loops().data()); } @@ -1255,7 +1255,7 @@ float (*BKE_mesh_orco_verts_get(Object *ob))[3] /* Get appropriate vertex coordinates */ float(*vcos)[3] = (float(*)[3])MEM_calloc_arrayN(me->totvert, sizeof(*vcos), "orco mesh"); - const Span verts = tme->vertices(); + const Span verts = tme->verts(); int totvert = min_ii(tme->totvert, me->totvert); @@ -1430,7 +1430,7 @@ void BKE_mesh_material_remap(Mesh *me, const uint *remap, uint remap_len) void BKE_mesh_smooth_flag_set(Mesh *me, const bool use_smooth) { - MutableSpan polys = me->polygons_for_write(); + MutableSpan polys = me->polys_for_write(); if (use_smooth) { for (MPoly &poly : polys) { poly.flag |= ME_SMOOTH; @@ -1518,7 +1518,7 @@ bool BKE_mesh_minmax(const Mesh *me, float r_min[3], float r_max[3]) float3 min; float3 max; }; - const Span verts = me->vertices(); + const Span verts = me->verts(); const Result minmax = threading::parallel_reduce( verts.index_range(), @@ -1543,7 +1543,7 @@ bool BKE_mesh_minmax(const Mesh *me, float r_min[3], float r_max[3]) void BKE_mesh_transform(Mesh *me, const float mat[4][4], bool do_keys) { - MutableSpan verts = me->vertices_for_write(); + MutableSpan verts = me->verts_for_write(); for (MVert &vert : verts) { mul_m4_v3(mat, vert.co); @@ -1577,7 +1577,7 @@ void BKE_mesh_transform(Mesh *me, const float mat[4][4], bool do_keys) void BKE_mesh_translate(Mesh *me, const float offset[3], const bool do_keys) { - MutableSpan verts = me->vertices_for_write(); + MutableSpan verts = me->verts_for_write(); for (MVert &vert : verts) { add_v3_v3(vert.co, offset); } @@ -1605,7 +1605,7 @@ void BKE_mesh_do_versions_cd_flag_init(Mesh *mesh) return; } - const Span verts = mesh->vertices(); + const Span verts = mesh->verts(); const Span edges = mesh->edges(); for (const MVert &vert : verts) { @@ -1648,9 +1648,9 @@ void BKE_mesh_mselect_validate(Mesh *me) if (me->totselect == 0) { return; } - const Span verts = me->vertices(); + const Span verts = me->verts(); const Span edges = me->edges(); - const Span polys = me->polygons(); + const Span polys = me->polys(); mselect_src = me->mselect; mselect_dst = (MSelect *)MEM_malloc_arrayN( @@ -1778,7 +1778,7 @@ float (*BKE_mesh_vert_coords_alloc(const Mesh *mesh, int *r_vert_len))[3] void BKE_mesh_vert_coords_apply(Mesh *mesh, const float (*vert_coords)[3]) { - MutableSpan verts = mesh->vertices_for_write(); + MutableSpan verts = mesh->verts_for_write(); for (const int i : verts.index_range()) { copy_v3_v3(verts[i].co, vert_coords[i]); } @@ -1789,7 +1789,7 @@ void BKE_mesh_vert_coords_apply_with_mat4(Mesh *mesh, const float (*vert_coords)[3], const float mat[4][4]) { - MutableSpan verts = mesh->vertices_for_write(); + MutableSpan verts = mesh->verts_for_write(); for (const int i : verts.index_range()) { mul_v3_m4v3(verts[i].co, mat, vert_coords[i]); } @@ -1827,9 +1827,9 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, /* may be nullptr */ clnors = (short(*)[2])CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL); - const Span verts = mesh->vertices(); + const Span verts = mesh->verts(); const Span edges = mesh->edges(); - const Span polys = mesh->polygons(); + const Span polys = mesh->polys(); const Span loops = mesh->loops(); BKE_mesh_normals_loop_split(verts.data(), @@ -1965,7 +1965,7 @@ static int split_faces_prepare_new_edges(Mesh *mesh, int num_edges = mesh->totedge; MutableSpan edges = mesh->edges_for_write(); MutableSpan loops = mesh->loops_for_write(); - const Span polys = mesh->polygons(); + const Span polys = mesh->polys(); BLI_bitmap *edges_used = BLI_BITMAP_NEW(num_edges, __func__); EdgeHash *edges_hash = BLI_edgehash_new_ex(__func__, num_edges); -- cgit v1.2.3 From 967664d1ee2f40a85301b1a8ccdb0ba3fe811d5d Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Wed, 7 Sep 2022 13:15:34 +0200 Subject: BLI: new C++ BitVector data structure This adds a new `blender::BitVector` data structure that was requested a couple of times. It also replaces usages of `BLI_bitmap` in C++ code. See the comment in `BLI_bit_vector.hh` for more details about the advantages and disadvantages of using a bit-vector and how the new data structure compares to `std::vector` and `BLI_bitmap`. Differential Revision: https://developer.blender.org/D14006 --- source/blender/blenkernel/intern/mesh.cc | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) (limited to 'source/blender/blenkernel/intern/mesh.cc') diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 361eb9bcbbe..1bf068fcd45 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -17,7 +17,7 @@ #include "DNA_meshdata_types.h" #include "DNA_object_types.h" -#include "BLI_bitmap.h" +#include "BLI_bit_vector.hh" #include "BLI_edgehash.h" #include "BLI_endian_switch.h" #include "BLI_ghash.h" @@ -64,6 +64,7 @@ #include "BLO_read_write.h" +using blender::BitVector; using blender::float3; using blender::MutableSpan; using blender::Span; @@ -1892,8 +1893,8 @@ static int split_faces_prepare_new_verts(Mesh *mesh, BKE_mesh_vertex_normals_ensure(mesh); float(*vert_normals)[3] = BKE_mesh_vertex_normals_for_write(mesh); - BLI_bitmap *verts_used = BLI_BITMAP_NEW(verts_len, __func__); - BLI_bitmap *done_loops = BLI_BITMAP_NEW(loops_len, __func__); + BitVector<> verts_used(verts_len, false); + BitVector<> done_loops(loops_len, false); MLoop *ml = loops.data(); MLoopNorSpace **lnor_space = lnors_spacearr->lspacearr; @@ -1901,9 +1902,9 @@ static int split_faces_prepare_new_verts(Mesh *mesh, BLI_assert(lnors_spacearr->data_type == MLNOR_SPACEARR_LOOP_INDEX); for (int loop_idx = 0; loop_idx < loops_len; loop_idx++, ml++, lnor_space++) { - if (!BLI_BITMAP_TEST(done_loops, loop_idx)) { + if (!done_loops[loop_idx]) { const int vert_idx = ml->v; - const bool vert_used = BLI_BITMAP_TEST_BOOL(verts_used, vert_idx); + const bool vert_used = verts_used[vert_idx]; /* If vert is already used by another smooth fan, we need a new vert for this one. */ const int new_vert_idx = vert_used ? verts_len++ : vert_idx; @@ -1912,7 +1913,7 @@ static int split_faces_prepare_new_verts(Mesh *mesh, if ((*lnor_space)->flags & MLNOR_SPACE_IS_SINGLE) { /* Single loop in this fan... */ BLI_assert(POINTER_AS_INT((*lnor_space)->loops) == loop_idx); - BLI_BITMAP_ENABLE(done_loops, loop_idx); + done_loops[loop_idx].set(); if (vert_used) { ml->v = new_vert_idx; } @@ -1920,7 +1921,7 @@ static int split_faces_prepare_new_verts(Mesh *mesh, else { for (LinkNode *lnode = (*lnor_space)->loops; lnode; lnode = lnode->next) { const int ml_fan_idx = POINTER_AS_INT(lnode->link); - BLI_BITMAP_ENABLE(done_loops, ml_fan_idx); + done_loops[ml_fan_idx].set(); if (vert_used) { loops[ml_fan_idx].v = new_vert_idx; } @@ -1928,7 +1929,7 @@ static int split_faces_prepare_new_verts(Mesh *mesh, } if (!vert_used) { - BLI_BITMAP_ENABLE(verts_used, vert_idx); + verts_used[vert_idx].set(); /* We need to update that vertex's normal here, we won't go over it again. */ /* This is important! *DO NOT* set vnor to final computed lnor, * vnor should always be defined to 'automatic normal' value computed from its polys, @@ -1949,9 +1950,6 @@ static int split_faces_prepare_new_verts(Mesh *mesh, } } - MEM_freeN(done_loops); - MEM_freeN(verts_used); - return verts_len - mesh->totvert; } @@ -1967,7 +1965,7 @@ static int split_faces_prepare_new_edges(Mesh *mesh, MutableSpan loops = mesh->loops_for_write(); const Span polys = mesh->polys(); - BLI_bitmap *edges_used = BLI_BITMAP_NEW(num_edges, __func__); + BitVector<> edges_used(num_edges, false); EdgeHash *edges_hash = BLI_edgehash_new_ex(__func__, num_edges); const MPoly *mp = polys.data(); @@ -1980,7 +1978,7 @@ static int split_faces_prepare_new_edges(Mesh *mesh, const int edge_idx = ml_prev->e; /* That edge has not been encountered yet, define it. */ - if (BLI_BITMAP_TEST(edges_used, edge_idx)) { + if (edges_used[edge_idx]) { /* Original edge has already been used, we need to define a new one. */ const int new_edge_idx = num_edges++; *eval = POINTER_FROM_INT(new_edge_idx); @@ -2000,7 +1998,7 @@ static int split_faces_prepare_new_edges(Mesh *mesh, edges[edge_idx].v1 = ml_prev->v; edges[edge_idx].v2 = ml->v; *eval = POINTER_FROM_INT(edge_idx); - BLI_BITMAP_ENABLE(edges_used, edge_idx); + edges_used[edge_idx].set(); } } else { @@ -2012,7 +2010,6 @@ static int split_faces_prepare_new_edges(Mesh *mesh, } } - MEM_freeN(edges_used); BLI_edgehash_free(edges_hash, nullptr); return num_edges - mesh->totedge; -- cgit v1.2.3 From 0a32f6b76a63dce674cbee5b402f7054354e8f59 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Wed, 7 Sep 2022 14:33:29 -0500 Subject: Fix T100863, T100875: Vertex group reading broken for recent files This patch consists of two related fixes. The first is a simple fix for forward compatibility, setting the Mesh.dvert pointer when writing a file allows old Blender versions to read vertex groups from newly saved files. The second part is a bit uglier and more complex. Normally mesh vertex group data is read in mesh_blend_read_data, for backward compatibility with very old files. However, after 05952aa94d33eeb50 the mesh.dvert pointer was not set, so the data was not read. Reading vertex group layers when reading custom data is enough to fix that issue. We need to read the data from *both* places, but BKE_defvert_blend_read cannot run twice without memory leaks, so first try reading from custom data, then read the pointer if that fails. Differential Revision: https://developer.blender.org/D15905 --- source/blender/blenkernel/intern/mesh.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'source/blender/blenkernel/intern/mesh.cc') diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 1bf068fcd45..84fc9005d53 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -249,7 +249,6 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address else { Set names_to_skip; if (!BLO_write_is_undo(writer)) { - BKE_mesh_legacy_convert_hide_layers_to_flags(mesh); BKE_mesh_legacy_convert_material_indices_to_mpoly(mesh); /* When converting to the old mesh format, don't save redundant attributes. */ @@ -260,6 +259,7 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address mesh->medge = const_cast(mesh->edges().data()); mesh->mpoly = const_cast(mesh->polys().data()); mesh->mloop = const_cast(mesh->loops().data()); + mesh->dvert = const_cast(mesh->deform_verts().data()); } CustomData_blend_write_prepare(mesh->vdata, vert_layers, names_to_skip); @@ -314,9 +314,6 @@ static void mesh_blend_read_data(BlendDataReader *reader, ID *id) BLO_read_data_address(reader, &mesh->adt); BKE_animdata_blend_read_data(reader, mesh->adt); - /* Normally BKE_defvert_blend_read should be called in CustomData_blend_read, - * but for backwards compatibility in do_versions to work we do it here. */ - BKE_defvert_blend_read(reader, mesh->totvert, mesh->dvert); BLO_read_list(reader, &mesh->vertex_group_names); CustomData_blend_read(reader, &mesh->vdata, mesh->totvert); @@ -324,6 +321,11 @@ static void mesh_blend_read_data(BlendDataReader *reader, ID *id) CustomData_blend_read(reader, &mesh->fdata, mesh->totface); CustomData_blend_read(reader, &mesh->ldata, mesh->totloop); CustomData_blend_read(reader, &mesh->pdata, mesh->totpoly); + if (mesh->deform_verts().is_empty()) { + /* Vertex group data was also an owning pointer in old Blender versions. + * Don't read them again if they were read as part of #CustomData. */ + BKE_defvert_blend_read(reader, mesh->totvert, mesh->dvert); + } mesh->texflag &= ~ME_AUTOSPACE_EVALUATED; mesh->edit_mesh = nullptr; -- cgit v1.2.3 From d5934974219135102f364f57c45a8b1465e2b8d9 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Wed, 7 Sep 2022 21:41:39 -0500 Subject: Cleanup: Use C++ methods to retrieve attribute accessors Replace `mesh_attributes`, `mesh_attributes_for_write` and the point cloud versions with methods on the `Mesh` and `PointCloud` types. This makes them friendlier to use and improves readability. Differential Revision: https://developer.blender.org/D15907 --- source/blender/blenkernel/intern/mesh.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'source/blender/blenkernel/intern/mesh.cc') diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 84fc9005d53..6b99085ea28 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -1343,7 +1343,7 @@ void BKE_mesh_material_index_remove(Mesh *me, short index) { using namespace blender; using namespace blender::bke; - MutableAttributeAccessor attributes = mesh_attributes_for_write(*me); + MutableAttributeAccessor attributes = me->attributes_for_write(); AttributeWriter material_indices = attributes.lookup_for_write("material_index"); if (!material_indices) { return; @@ -1368,7 +1368,7 @@ bool BKE_mesh_material_index_used(Mesh *me, short index) { using namespace blender; using namespace blender::bke; - const AttributeAccessor attributes = mesh_attributes(*me); + const AttributeAccessor attributes = me->attributes(); const VArray material_indices = attributes.lookup_or_default( "material_index", ATTR_DOMAIN_FACE, 0); if (material_indices.is_single()) { @@ -1382,7 +1382,7 @@ void BKE_mesh_material_index_clear(Mesh *me) { using namespace blender; using namespace blender::bke; - MutableAttributeAccessor attributes = mesh_attributes_for_write(*me); + MutableAttributeAccessor attributes = me->attributes_for_write(); attributes.remove("material_index"); BKE_mesh_tessface_clear(me); @@ -1411,7 +1411,7 @@ void BKE_mesh_material_remap(Mesh *me, const uint *remap, uint remap_len) } } else { - MutableAttributeAccessor attributes = mesh_attributes_for_write(*me); + MutableAttributeAccessor attributes = me->attributes_for_write(); AttributeWriter material_indices = attributes.lookup_for_write("material_index"); if (!material_indices) { return; @@ -1763,7 +1763,7 @@ void BKE_mesh_count_selected_items(const Mesh *mesh, int r_count[3]) void BKE_mesh_vert_coords_get(const Mesh *mesh, float (*vert_coords)[3]) { - blender::bke::AttributeAccessor attributes = blender::bke::mesh_attributes(*mesh); + blender::bke::AttributeAccessor attributes = mesh->attributes(); VArray positions = attributes.lookup_or_default( "position", ATTR_DOMAIN_POINT, float3(0)); positions.materialize({(float3 *)vert_coords, mesh->totvert}); -- cgit v1.2.3 From 406243c2fde7472ea39f1eb6316311aec5b72e13 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Thu, 8 Sep 2022 16:32:35 +0200 Subject: IDManagement: change `IDTypeInfo.owner_get` to instead return address of the owner_id pointer. Also rename the callback. That way, we can keep moving toward a more generic handling of those embedded IDs (think e.g. about copy code). --- source/blender/blenkernel/intern/mesh.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender/blenkernel/intern/mesh.cc') diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 6b99085ea28..8254bb953d2 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -402,7 +402,7 @@ IDTypeInfo IDType_ID_ME = { /* foreach_id */ mesh_foreach_id, /* foreach_cache */ nullptr, /* foreach_path */ mesh_foreach_path, - /* owner_get */ nullptr, + /* owner_pointer_get */ nullptr, /* blend_write */ mesh_blend_write, /* blend_read_data */ mesh_blend_read_data, -- cgit v1.2.3 From 21f2bacad977d3fd83d9e4730f2a14dc9932f043 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Fri, 9 Sep 2022 08:24:31 -0500 Subject: Cleanup: Simplify BKE_mesh_nomain_to_mesh - Remove "take ownership" argument which was confusing and always true - The argument made ownership very confusing - Better to avoid boolean arguments that switch a function's purpose - Remove "mask" argument which was basically wrong and not used properly - "EVERYTHING" was used because developers are wary of removing data - Instead use `CD_MASK_MESH` for its purpose of original mesh data - Remove use of shallow copied temporary mesh, which is unnecessary now - Split shape key processing into separate functions and use C++ types - Copy fields explicitly rather than using memcpy for the whole struct - Use higher level functions and avoid redundant code - The whole idea is pretty simple and can be built from standard logic - Adjust `CustomData` logic to be consistent with "assign" expectations - Clear the layer data from the source, and moves the anonymous ID Differential Revision: https://developer.blender.org/D15857 --- source/blender/blenkernel/intern/mesh.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'source/blender/blenkernel/intern/mesh.cc') diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 8254bb953d2..c82d9be008d 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -881,11 +881,12 @@ static void mesh_clear_geometry(Mesh *mesh) mesh->totpoly = 0; mesh->act_face = -1; mesh->totselect = 0; + + BLI_freelistN(&mesh->vertex_group_names); } void BKE_mesh_clear_geometry(Mesh *mesh) { - BKE_animdata_free(&mesh->id, false); BKE_mesh_runtime_clear_cache(mesh); mesh_clear_geometry(mesh); } @@ -975,6 +976,7 @@ void BKE_mesh_copy_parameters(Mesh *me_dst, const Mesh *me_src) copy_v3_v3(me_dst->size, me_src->size); me_dst->vertex_group_active_index = me_src->vertex_group_active_index; + me_dst->attributes_active_index = me_src->attributes_active_index; } void BKE_mesh_copy_parameters_for_eval(Mesh *me_dst, const Mesh *me_src) -- cgit v1.2.3 From 291c313f80b4cccc8fcce3035584caeaa654844f Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Fri, 9 Sep 2022 08:29:07 -0500 Subject: Mesh: Move bevel weight out of MVert and MEdge As described in T95966, the goal is to move to a "struct of arrays" approach rather than gathering an arbitrary set of data in hard-coded structs. This has performance benefits, but also code complexity benefits (this patch removes plenty of code, though the boilerplate for the new operators outweighs that here). To mirror the internal change, the options for storing mesh bevel weights are converted into operators that add or remove the layer, like for some other layers. The most complex change is to the solidify modifier, where bevel weights had special handling. Other than that, most changes are removing clearing of the weights, boilerplate for the add/remove operators, and removing the manual transfer of bevel weights in bmesh - mesh conversion. Eventually bevel weights can become a fully generic attribute, but for now this patch aims to avoid most functional changes. Bevel weights are still written and read from the mesh in the old way, so neither forward nor backward compatibility are affected. As described in T95965, writing in the old format will be done until 4.0. Differential Revision: https://developer.blender.org/D14077 --- source/blender/blenkernel/intern/mesh.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'source/blender/blenkernel/intern/mesh.cc') diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index c82d9be008d..a5b50824542 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -251,6 +251,7 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address if (!BLO_write_is_undo(writer)) { BKE_mesh_legacy_convert_hide_layers_to_flags(mesh); BKE_mesh_legacy_convert_material_indices_to_mpoly(mesh); + BKE_mesh_legacy_bevel_weight_from_layers(mesh); /* When converting to the old mesh format, don't save redundant attributes. */ names_to_skip.add_multiple_new({".hide_vert", ".hide_edge", ".hide_poly"}); @@ -348,6 +349,7 @@ static void mesh_blend_read_data(BlendDataReader *reader, ID *id) if (!BLO_read_data_is_undo(reader)) { BKE_mesh_legacy_convert_flags_to_hide_layers(mesh); BKE_mesh_legacy_convert_mpoly_to_material_indices(mesh); + BKE_mesh_legacy_bevel_weight_to_layers(mesh); } /* We don't expect to load normals from files, since they are derived data. */ -- cgit v1.2.3 From 352d55b1c88776e52050db1adc6a5aa1da13596e Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Fri, 9 Sep 2022 15:05:05 -0500 Subject: Mesh: Avoid saving redundant generic material index attribute This attribute is still read and written in the legacy format which puts it inside of `MPoly`. Missed in f1c0249f34c4171ec. --- source/blender/blenkernel/intern/mesh.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender/blenkernel/intern/mesh.cc') diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index a5b50824542..a0548b7efd4 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -253,7 +253,7 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address BKE_mesh_legacy_convert_material_indices_to_mpoly(mesh); BKE_mesh_legacy_bevel_weight_from_layers(mesh); /* When converting to the old mesh format, don't save redundant attributes. */ - names_to_skip.add_multiple_new({".hide_vert", ".hide_edge", ".hide_poly"}); + names_to_skip.add_multiple_new({".hide_vert", ".hide_edge", ".hide_poly", "material_index"}); /* Set deprecated mesh data pointers for forward compatibility. */ mesh->mvert = const_cast(mesh->verts().data()); -- cgit v1.2.3 From 9088a1f4764f371f7f22384e7d7e2c8971d5c9f0 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Mon, 12 Sep 2022 11:35:33 -0500 Subject: Geometry: Avoid unnecessary initialization when resizing data arrays When resizing mesh and curves attribute storage, avoid initializing the new memory for basic types. Also, avoid skipping "no free" layers; all layers should be reallocated to the new size since they may be accessed. The semantics introduced in 25237d2625078c6d1 are essential for this change, because otherwise we don't have a way to construct non-trivial types in the new memory. In a basic test of the extrude node, I observed a performance improvement of about 30%, from 55ms to 42ms. Differential Revision: https://developer.blender.org/D15818 --- source/blender/blenkernel/intern/mesh.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'source/blender/blenkernel/intern/mesh.cc') diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index a0548b7efd4..636be0dc032 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -2095,11 +2095,11 @@ void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals) const bool do_edges = (num_new_edges > 0); /* Reallocate all vert and edge related data. */ + CustomData_realloc(&mesh->vdata, mesh->totvert, mesh->totvert + num_new_verts); mesh->totvert += num_new_verts; - CustomData_realloc(&mesh->vdata, mesh->totvert); if (do_edges) { + CustomData_realloc(&mesh->edata, mesh->totedge, mesh->totedge + num_new_edges); mesh->totedge += num_new_edges; - CustomData_realloc(&mesh->edata, mesh->totedge); } /* Update normals manually to avoid recalculation after this operation. */ -- cgit v1.2.3 From ad245f1970343ed41098ed9611a38b167fd757d4 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Mon, 12 Sep 2022 17:17:11 -0500 Subject: Fix T101013: Reordering materials broken with only one assigned When there was only a single material assigned to the mesh, the material index attribute didn't necessarily exist. Changing the oder of the slots wouldn't change the first material index as necessary. --- source/blender/blenkernel/intern/mesh.cc | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'source/blender/blenkernel/intern/mesh.cc') diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 636be0dc032..8616b056d7f 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -1416,19 +1416,15 @@ void BKE_mesh_material_remap(Mesh *me, const uint *remap, uint remap_len) } else { MutableAttributeAccessor attributes = me->attributes_for_write(); - AttributeWriter material_indices = attributes.lookup_for_write("material_index"); + SpanAttributeWriter material_indices = attributes.lookup_or_add_for_write_span( + "material_index", ATTR_DOMAIN_FACE); if (!material_indices) { return; } - if (material_indices.domain != ATTR_DOMAIN_FACE) { - BLI_assert_unreachable(); - return; - } - MutableVArraySpan indices_span(material_indices.varray); - for (const int i : indices_span.index_range()) { - MAT_NR_REMAP(indices_span[i]); + for (const int i : material_indices.span.index_range()) { + MAT_NR_REMAP(material_indices.span[i]); } - indices_span.save(); + material_indices.span.save(); material_indices.finish(); } -- cgit v1.2.3 From 08a8de739d8c7fa60f257ed171d292879edae013 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Tue, 13 Sep 2022 11:43:34 -0500 Subject: Fix: Resolve deprecation warning when copying polygon struct `MPoly` is used and copied in many places. To avoid the need to use a special function for copying MPoly, or the need to add a copy constructor, just rename the `mat_nr` field to include "legacy" in the name. This keeps the original purpose of notifying developers that the field shouldn't be used without any further complexity. Apply the same fix to `bweight`. Differential Revision: https://developer.blender.org/D15841 --- source/blender/blenkernel/intern/mesh.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'source/blender/blenkernel/intern/mesh.cc') diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 8616b056d7f..6bf25da5ae7 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -1612,14 +1612,14 @@ void BKE_mesh_do_versions_cd_flag_init(Mesh *mesh) const Span edges = mesh->edges(); for (const MVert &vert : verts) { - if (vert.bweight != 0) { + if (vert.bweight_legacy != 0) { mesh->cd_flag |= ME_CDFLAG_VERT_BWEIGHT; break; } } for (const MEdge &edge : edges) { - if (edge.bweight != 0) { + if (edge.bweight_legacy != 0) { mesh->cd_flag |= ME_CDFLAG_EDGE_BWEIGHT; if (mesh->cd_flag & ME_CDFLAG_EDGE_CREASE) { break; -- cgit v1.2.3 From 818c9e524d82d3eff40504e7d0e5293961983155 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Wed, 14 Sep 2022 11:31:52 -0500 Subject: Fix: Mesh SoA format conversion skips versioning Converting to the SoA format (T95965) immediately when reading meshes means that none of the changes from versioning would be applied first. This means important fixes like f14995aba70a aren't properly applied, so modifications could be done to invalid CustomData. To fix this, move the SoA changes into versioning code, in a new versioning_400.cc file. Differential Revision: https://developer.blender.org/D15919 --- source/blender/blenkernel/intern/mesh.cc | 6 ------ 1 file changed, 6 deletions(-) (limited to 'source/blender/blenkernel/intern/mesh.cc') diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 6bf25da5ae7..7da9acc3cf6 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -346,12 +346,6 @@ static void mesh_blend_read_data(BlendDataReader *reader, ID *id) } } - if (!BLO_read_data_is_undo(reader)) { - BKE_mesh_legacy_convert_flags_to_hide_layers(mesh); - BKE_mesh_legacy_convert_mpoly_to_material_indices(mesh); - BKE_mesh_legacy_bevel_weight_to_layers(mesh); - } - /* We don't expect to load normals from files, since they are derived data. */ BKE_mesh_normals_tag_dirty(mesh); BKE_mesh_assert_normals_dirty_or_calculated(mesh); -- cgit v1.2.3