Files
test/source/blender/editors/mesh/editface.cc

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

1222 lines
38 KiB
C++
Raw Normal View History

/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup edmesh
2011-02-27 20:29:51 +00:00
*/
#include "BLI_atomic_disjoint_set.hh"
#include "BLI_math_matrix.h"
#include "BLI_math_vector.h"
#include "BLI_math_vector.hh"
#include "BLI_task.hh"
#include "BLI_vector_set.hh"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "BKE_attribute.hh"
#include "BKE_context.hh"
#include "BKE_customdata.hh"
#include "BKE_mesh.hh"
#include "BKE_mesh_mapping.hh"
#include "BKE_object.hh"
#include "ED_mesh.hh"
#include "ED_screen.hh"
#include "ED_select_utils.hh"
#include "ED_view3d.hh"
#include "WM_api.hh"
#include "WM_types.hh"
#include "DEG_depsgraph.hh"
#include "DEG_depsgraph_query.hh"
/* own include */
void paintface_flush_flags(bContext *C,
Object *ob,
const bool flush_selection,
const bool flush_hidden)
{
using namespace blender;
Mesh *mesh = BKE_mesh_from_object(ob);
const int *index_array = nullptr;
BLI_assert(flush_selection || flush_hidden);
if (mesh == nullptr) {
return;
2019-04-22 09:19:45 +10:00
}
/* NOTE: call #BKE_mesh_flush_hidden_from_verts_ex first when changing hidden flags. */
/* we could call this directly in all areas that change selection,
* since this could become slow for realtime updates (circle-select for eg) */
if (flush_selection) {
bke::mesh_select_face_flush(*mesh);
}
Refactor access to dependency graph This change ensures that operators which needs access to evaluated data first makes sure there is a dependency graph. Other accesses to the dependency graph made it more explicit about whether they just need a valid dependency graph pointer or whether they expect the graph to be already evaluated. This replaces OPTYPE_USE_EVAL_DATA which is now removed. Some general rules about usage of accessors: - Drawing is expected to happen from a fully evaluated dependency graph. There is now a function to access it, which will in the future control that dependency graph is actually evaluated. This check is not yet done because there are some things to be taken care about first: for example, post-update hooks might leave scene in a state where something is still tagged for update. - All operators which needs to access evaluated state must use CTX_data_ensure_evaluated_depsgraph(). This function replaces OPTYPE_USE_EVAL_DATA. The call is generally to be done in the very beginning of the operator, prior other logic (unless this is some comprehensive operator which might or might not need access to an evaluated state). This call is never to be used from a loop. If some utility function requires evaluated state of dependency graph the graph is to be passed as an explicit argument. This way it is clear that no evaluation happens in a loop or something like this. - All cases which needs to know dependency graph pointer, but which doesn't want to actually evaluate it can use old-style function CTX_data_depsgraph_pointer(), assuming that underlying code will ensure dependency graph is evaluated prior to accessing it. - The new functions are replacing OPTYPE_USE_EVAL_DATA, so now it is explicit and local about where dependency graph is being ensured. This commit also contains some fixes of wrong usage of evaluation functions on original objects. Ideally should be split out, but in reality with all the APIs being renamed is quite tricky. Fixes T67454: Blender crash on rapid undo and select Speculation here is that sometimes undo and selection operators are sometimes handled in the same event loop iteration, which leaves non-evaluated dependency graph. Fixes T67973: Crash on Fix Deforms operator Fixes T67902: Crash when undo a loop cut Reviewers: brecht Reviewed By: brecht Subscribers: lichtwerk Maniphest Tasks: T67454 Differential Revision: https://developer.blender.org/D5343
2019-07-25 16:36:22 +02:00
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
if (ob_eval == nullptr) {
return;
}
bke::AttributeAccessor attributes_me = mesh->attributes();
Mesh *me_orig = (Mesh *)ob_eval->runtime->data_orig;
bke::MutableAttributeAccessor attributes_orig = me_orig->attributes_for_write();
Mesh *mesh_eval = (Mesh *)ob_eval->runtime->data_eval;
bke::MutableAttributeAccessor attributes_eval = mesh_eval->attributes_for_write();
bool updated = false;
if (me_orig != nullptr && mesh_eval != nullptr && me_orig->faces_num == mesh->faces_num) {
/* Update the evaluated copy of the mesh. */
if (flush_hidden) {
const VArray<bool> hide_poly_me = *attributes_me.lookup_or_default<bool>(
".hide_poly", bke::AttrDomain::Face, false);
bke::SpanAttributeWriter<bool> hide_poly_orig =
attributes_orig.lookup_or_add_for_write_only_span<bool>(".hide_poly",
bke::AttrDomain::Face);
hide_poly_me.materialize(hide_poly_orig.span);
hide_poly_orig.finish();
}
2022-09-23 09:38:37 -05:00
if (flush_selection) {
const VArray<bool> select_poly_me = *attributes_me.lookup_or_default<bool>(
".select_poly", bke::AttrDomain::Face, false);
2022-09-23 09:38:37 -05:00
bke::SpanAttributeWriter<bool> select_poly_orig =
attributes_orig.lookup_or_add_for_write_only_span<bool>(".select_poly",
bke::AttrDomain::Face);
2022-09-23 09:38:37 -05:00
select_poly_me.materialize(select_poly_orig.span);
select_poly_orig.finish();
}
/* Mesh faces => Final derived faces */
if ((index_array = (const int *)CustomData_get_layer(&mesh_eval->face_data, CD_ORIGINDEX))) {
2022-09-23 09:38:37 -05:00
if (flush_hidden) {
const VArray<bool> hide_poly_orig = *attributes_orig.lookup_or_default<bool>(
".hide_poly", bke::AttrDomain::Face, false);
2022-09-23 09:38:37 -05:00
bke::SpanAttributeWriter<bool> hide_poly_eval =
attributes_eval.lookup_or_add_for_write_only_span<bool>(".hide_poly",
bke::AttrDomain::Face);
for (const int i : IndexRange(mesh_eval->faces_num)) {
const int orig_face_index = index_array[i];
if (orig_face_index != ORIGINDEX_NONE) {
hide_poly_eval.span[i] = hide_poly_orig[orig_face_index];
2022-09-23 09:38:37 -05:00
}
}
2022-09-23 09:38:37 -05:00
hide_poly_eval.finish();
}
2022-09-23 09:38:37 -05:00
if (flush_selection) {
const VArray<bool> select_poly_orig = *attributes_orig.lookup_or_default<bool>(
".select_poly", bke::AttrDomain::Face, false);
2022-09-23 09:38:37 -05:00
bke::SpanAttributeWriter<bool> select_poly_eval =
attributes_eval.lookup_or_add_for_write_only_span<bool>(".select_poly",
bke::AttrDomain::Face);
for (const int i : IndexRange(mesh_eval->faces_num)) {
const int orig_face_index = index_array[i];
if (orig_face_index != ORIGINDEX_NONE) {
select_poly_eval.span[i] = select_poly_orig[orig_face_index];
2022-09-23 09:38:37 -05:00
}
}
2022-09-23 09:38:37 -05:00
select_poly_eval.finish();
}
updated = true;
2011-10-14 09:05:20 +00:00
}
}
if (updated) {
if (flush_hidden) {
BKE_mesh_batch_cache_dirty_tag(mesh_eval, BKE_MESH_BATCH_DIRTY_ALL);
}
else {
BKE_mesh_batch_cache_dirty_tag(mesh_eval, BKE_MESH_BATCH_DIRTY_SELECT_PAINT);
}
DEG_id_tag_update(static_cast<ID *>(ob->data), ID_RECALC_SELECT);
}
else {
DEG_id_tag_update(static_cast<ID *>(ob->data), ID_RECALC_SYNC_TO_EVAL | ID_RECALC_SELECT);
}
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
}
void paintface_hide(bContext *C, Object *ob, const bool unselected)
{
using namespace blender;
Mesh *mesh = BKE_mesh_from_object(ob);
if (mesh == nullptr || mesh->faces_num == 0) {
return;
2019-04-22 09:19:45 +10:00
}
bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
bke::SpanAttributeWriter<bool> hide_poly = attributes.lookup_or_add_for_write_span<bool>(
".hide_poly", bke::AttrDomain::Face);
2022-09-23 09:38:37 -05:00
bke::SpanAttributeWriter<bool> select_poly = attributes.lookup_or_add_for_write_span<bool>(
".select_poly", bke::AttrDomain::Face);
for (int i = 0; i < mesh->faces_num; i++) {
if (!hide_poly.span[i]) {
2022-09-23 09:38:37 -05:00
if (!select_poly.span[i] == unselected) {
hide_poly.span[i] = true;
}
}
if (hide_poly.span[i]) {
2022-09-23 09:38:37 -05:00
select_poly.span[i] = false;
}
}
hide_poly.finish();
2022-09-23 09:38:37 -05:00
select_poly.finish();
bke::mesh_hide_face_flush(*mesh);
paintface_flush_flags(C, ob, true, true);
}
void paintface_reveal(bContext *C, Object *ob, const bool select)
{
using namespace blender;
Mesh *mesh = BKE_mesh_from_object(ob);
if (mesh == nullptr || mesh->faces_num == 0) {
return;
2019-04-22 09:19:45 +10:00
}
bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
if (select) {
const VArray<bool> hide_poly = *attributes.lookup_or_default<bool>(
".hide_poly", bke::AttrDomain::Face, false);
2022-09-23 09:38:37 -05:00
bke::SpanAttributeWriter<bool> select_poly = attributes.lookup_or_add_for_write_span<bool>(
".select_poly", bke::AttrDomain::Face);
2022-09-23 09:38:37 -05:00
for (const int i : hide_poly.index_range()) {
if (hide_poly[i]) {
2022-09-23 09:38:37 -05:00
select_poly.span[i] = true;
}
}
2022-09-23 09:38:37 -05:00
select_poly.finish();
}
attributes.remove(".hide_poly");
bke::mesh_hide_face_flush(*mesh);
paintface_flush_flags(C, ob, true, true);
}
/**
* Join all edges of each face in the #AtomicDisjointSet. This can be used to find out which faces
* are connected to each other.
* \param islands: Is expected to be of length `mesh->edges_num`.
* \param skip_seams: Faces separated by a seam will be treated as not connected.
*/
static void build_poly_connections(blender::AtomicDisjointSet &islands,
Mesh &mesh,
const bool skip_seams = true)
{
using namespace blender;
const OffsetIndices faces = mesh.faces();
Mesh: Replace MLoop struct with generic attributes Implements #102359. Split the `MLoop` struct into two separate integer arrays called `corner_verts` and `corner_edges`, referring to the vertex each corner is attached to and the next edge around the face at each corner. These arrays can be sliced to give access to the edges or vertices in a face. Then they are often referred to as "poly_verts" or "poly_edges". The main benefits are halving the necessary memory bandwidth when only one array is used and simplifications from using regular integer indices instead of a special-purpose struct. The commit also starts a renaming from "loop" to "corner" in mesh code. Like the other mesh struct of array refactors, forward compatibility is kept by writing files with the older format. This will be done until 4.0 to ease the transition process. Looking at a small portion of the patch should give a good impression for the rest of the changes. I tried to make the changes as small as possible so it's easy to tell the correctness from the diff. Though I found Blender developers have been very inventive over the last decade when finding different ways to loop over the corners in a face. For performance, nearly every piece of code that deals with `Mesh` is slightly impacted. Any algorithm that is memory bottle-necked should see an improvement. For example, here is a comparison of interpolating a vertex float attribute to face corners (Ryzen 3700x): **Before** (Average: 3.7 ms, Min: 3.4 ms) ``` threading::parallel_for(loops.index_range(), 4096, [&](IndexRange range) { for (const int64_t i : range) { dst[i] = src[loops[i].v]; } }); ``` **After** (Average: 2.9 ms, Min: 2.6 ms) ``` array_utils::gather(src, corner_verts, dst); ``` That's an improvement of 28% to the average timings, and it's also a simplification, since an index-based routine can be used instead. For more examples using the new arrays, see the design task. Pull Request: https://projects.blender.org/blender/blender/pulls/104424
2023-03-20 15:55:13 +01:00
const Span<int> corner_edges = mesh.corner_edges();
const bke::AttributeAccessor attributes = mesh.attributes();
const VArray<bool> uv_seams = *attributes.lookup_or_default<bool>(
"uv_seam", bke::AttrDomain::Edge, false);
const VArray<bool> hide_poly = *attributes.lookup_or_default<bool>(
".hide_poly", bke::AttrDomain::Face, false);
/* Faces are connected if they share edges. By connecting all edges of a loop (as long as they
* are not a seam) we can find connected faces. */
threading::parallel_for(faces.index_range(), 1024, [&](const IndexRange range) {
for (const int face_index : range) {
if (hide_poly[face_index]) {
continue;
2019-04-22 09:19:45 +10:00
}
const Span<int> face_edges = corner_edges.slice(faces[face_index]);
for (const int poly_loop_index : face_edges.index_range()) {
const int outer_edge = face_edges[poly_loop_index];
Mesh: Replace MLoop struct with generic attributes Implements #102359. Split the `MLoop` struct into two separate integer arrays called `corner_verts` and `corner_edges`, referring to the vertex each corner is attached to and the next edge around the face at each corner. These arrays can be sliced to give access to the edges or vertices in a face. Then they are often referred to as "poly_verts" or "poly_edges". The main benefits are halving the necessary memory bandwidth when only one array is used and simplifications from using regular integer indices instead of a special-purpose struct. The commit also starts a renaming from "loop" to "corner" in mesh code. Like the other mesh struct of array refactors, forward compatibility is kept by writing files with the older format. This will be done until 4.0 to ease the transition process. Looking at a small portion of the patch should give a good impression for the rest of the changes. I tried to make the changes as small as possible so it's easy to tell the correctness from the diff. Though I found Blender developers have been very inventive over the last decade when finding different ways to loop over the corners in a face. For performance, nearly every piece of code that deals with `Mesh` is slightly impacted. Any algorithm that is memory bottle-necked should see an improvement. For example, here is a comparison of interpolating a vertex float attribute to face corners (Ryzen 3700x): **Before** (Average: 3.7 ms, Min: 3.4 ms) ``` threading::parallel_for(loops.index_range(), 4096, [&](IndexRange range) { for (const int64_t i : range) { dst[i] = src[loops[i].v]; } }); ``` **After** (Average: 2.9 ms, Min: 2.6 ms) ``` array_utils::gather(src, corner_verts, dst); ``` That's an improvement of 28% to the average timings, and it's also a simplification, since an index-based routine can be used instead. For more examples using the new arrays, see the design task. Pull Request: https://projects.blender.org/blender/blender/pulls/104424
2023-03-20 15:55:13 +01:00
if (skip_seams && uv_seams[outer_edge]) {
continue;
}
Mesh: Replace MLoop struct with generic attributes Implements #102359. Split the `MLoop` struct into two separate integer arrays called `corner_verts` and `corner_edges`, referring to the vertex each corner is attached to and the next edge around the face at each corner. These arrays can be sliced to give access to the edges or vertices in a face. Then they are often referred to as "poly_verts" or "poly_edges". The main benefits are halving the necessary memory bandwidth when only one array is used and simplifications from using regular integer indices instead of a special-purpose struct. The commit also starts a renaming from "loop" to "corner" in mesh code. Like the other mesh struct of array refactors, forward compatibility is kept by writing files with the older format. This will be done until 4.0 to ease the transition process. Looking at a small portion of the patch should give a good impression for the rest of the changes. I tried to make the changes as small as possible so it's easy to tell the correctness from the diff. Though I found Blender developers have been very inventive over the last decade when finding different ways to loop over the corners in a face. For performance, nearly every piece of code that deals with `Mesh` is slightly impacted. Any algorithm that is memory bottle-necked should see an improvement. For example, here is a comparison of interpolating a vertex float attribute to face corners (Ryzen 3700x): **Before** (Average: 3.7 ms, Min: 3.4 ms) ``` threading::parallel_for(loops.index_range(), 4096, [&](IndexRange range) { for (const int64_t i : range) { dst[i] = src[loops[i].v]; } }); ``` **After** (Average: 2.9 ms, Min: 2.6 ms) ``` array_utils::gather(src, corner_verts, dst); ``` That's an improvement of 28% to the average timings, and it's also a simplification, since an index-based routine can be used instead. For more examples using the new arrays, see the design task. Pull Request: https://projects.blender.org/blender/blender/pulls/104424
2023-03-20 15:55:13 +01:00
for (const int inner_edge :
face_edges.slice(poly_loop_index, face_edges.size() - poly_loop_index))
{
Mesh: Replace MLoop struct with generic attributes Implements #102359. Split the `MLoop` struct into two separate integer arrays called `corner_verts` and `corner_edges`, referring to the vertex each corner is attached to and the next edge around the face at each corner. These arrays can be sliced to give access to the edges or vertices in a face. Then they are often referred to as "poly_verts" or "poly_edges". The main benefits are halving the necessary memory bandwidth when only one array is used and simplifications from using regular integer indices instead of a special-purpose struct. The commit also starts a renaming from "loop" to "corner" in mesh code. Like the other mesh struct of array refactors, forward compatibility is kept by writing files with the older format. This will be done until 4.0 to ease the transition process. Looking at a small portion of the patch should give a good impression for the rest of the changes. I tried to make the changes as small as possible so it's easy to tell the correctness from the diff. Though I found Blender developers have been very inventive over the last decade when finding different ways to loop over the corners in a face. For performance, nearly every piece of code that deals with `Mesh` is slightly impacted. Any algorithm that is memory bottle-necked should see an improvement. For example, here is a comparison of interpolating a vertex float attribute to face corners (Ryzen 3700x): **Before** (Average: 3.7 ms, Min: 3.4 ms) ``` threading::parallel_for(loops.index_range(), 4096, [&](IndexRange range) { for (const int64_t i : range) { dst[i] = src[loops[i].v]; } }); ``` **After** (Average: 2.9 ms, Min: 2.6 ms) ``` array_utils::gather(src, corner_verts, dst); ``` That's an improvement of 28% to the average timings, and it's also a simplification, since an index-based routine can be used instead. For more examples using the new arrays, see the design task. Pull Request: https://projects.blender.org/blender/blender/pulls/104424
2023-03-20 15:55:13 +01:00
if (outer_edge == inner_edge) {
continue;
}
Mesh: Replace MLoop struct with generic attributes Implements #102359. Split the `MLoop` struct into two separate integer arrays called `corner_verts` and `corner_edges`, referring to the vertex each corner is attached to and the next edge around the face at each corner. These arrays can be sliced to give access to the edges or vertices in a face. Then they are often referred to as "poly_verts" or "poly_edges". The main benefits are halving the necessary memory bandwidth when only one array is used and simplifications from using regular integer indices instead of a special-purpose struct. The commit also starts a renaming from "loop" to "corner" in mesh code. Like the other mesh struct of array refactors, forward compatibility is kept by writing files with the older format. This will be done until 4.0 to ease the transition process. Looking at a small portion of the patch should give a good impression for the rest of the changes. I tried to make the changes as small as possible so it's easy to tell the correctness from the diff. Though I found Blender developers have been very inventive over the last decade when finding different ways to loop over the corners in a face. For performance, nearly every piece of code that deals with `Mesh` is slightly impacted. Any algorithm that is memory bottle-necked should see an improvement. For example, here is a comparison of interpolating a vertex float attribute to face corners (Ryzen 3700x): **Before** (Average: 3.7 ms, Min: 3.4 ms) ``` threading::parallel_for(loops.index_range(), 4096, [&](IndexRange range) { for (const int64_t i : range) { dst[i] = src[loops[i].v]; } }); ``` **After** (Average: 2.9 ms, Min: 2.6 ms) ``` array_utils::gather(src, corner_verts, dst); ``` That's an improvement of 28% to the average timings, and it's also a simplification, since an index-based routine can be used instead. For more examples using the new arrays, see the design task. Pull Request: https://projects.blender.org/blender/blender/pulls/104424
2023-03-20 15:55:13 +01:00
if (skip_seams && uv_seams[inner_edge]) {
continue;
}
Mesh: Replace MLoop struct with generic attributes Implements #102359. Split the `MLoop` struct into two separate integer arrays called `corner_verts` and `corner_edges`, referring to the vertex each corner is attached to and the next edge around the face at each corner. These arrays can be sliced to give access to the edges or vertices in a face. Then they are often referred to as "poly_verts" or "poly_edges". The main benefits are halving the necessary memory bandwidth when only one array is used and simplifications from using regular integer indices instead of a special-purpose struct. The commit also starts a renaming from "loop" to "corner" in mesh code. Like the other mesh struct of array refactors, forward compatibility is kept by writing files with the older format. This will be done until 4.0 to ease the transition process. Looking at a small portion of the patch should give a good impression for the rest of the changes. I tried to make the changes as small as possible so it's easy to tell the correctness from the diff. Though I found Blender developers have been very inventive over the last decade when finding different ways to loop over the corners in a face. For performance, nearly every piece of code that deals with `Mesh` is slightly impacted. Any algorithm that is memory bottle-necked should see an improvement. For example, here is a comparison of interpolating a vertex float attribute to face corners (Ryzen 3700x): **Before** (Average: 3.7 ms, Min: 3.4 ms) ``` threading::parallel_for(loops.index_range(), 4096, [&](IndexRange range) { for (const int64_t i : range) { dst[i] = src[loops[i].v]; } }); ``` **After** (Average: 2.9 ms, Min: 2.6 ms) ``` array_utils::gather(src, corner_verts, dst); ``` That's an improvement of 28% to the average timings, and it's also a simplification, since an index-based routine can be used instead. For more examples using the new arrays, see the design task. Pull Request: https://projects.blender.org/blender/blender/pulls/104424
2023-03-20 15:55:13 +01:00
islands.join(inner_edge, outer_edge);
}
}
}
});
}
/* Select faces connected to the given face_indices. Seams are treated as separation. */
static void paintface_select_linked_faces(Mesh &mesh,
const blender::Span<int> face_indices,
const bool select)
{
using namespace blender;
AtomicDisjointSet islands(mesh.edges_num);
build_poly_connections(islands, mesh);
const OffsetIndices faces = mesh.faces();
Mesh: Replace MLoop struct with generic attributes Implements #102359. Split the `MLoop` struct into two separate integer arrays called `corner_verts` and `corner_edges`, referring to the vertex each corner is attached to and the next edge around the face at each corner. These arrays can be sliced to give access to the edges or vertices in a face. Then they are often referred to as "poly_verts" or "poly_edges". The main benefits are halving the necessary memory bandwidth when only one array is used and simplifications from using regular integer indices instead of a special-purpose struct. The commit also starts a renaming from "loop" to "corner" in mesh code. Like the other mesh struct of array refactors, forward compatibility is kept by writing files with the older format. This will be done until 4.0 to ease the transition process. Looking at a small portion of the patch should give a good impression for the rest of the changes. I tried to make the changes as small as possible so it's easy to tell the correctness from the diff. Though I found Blender developers have been very inventive over the last decade when finding different ways to loop over the corners in a face. For performance, nearly every piece of code that deals with `Mesh` is slightly impacted. Any algorithm that is memory bottle-necked should see an improvement. For example, here is a comparison of interpolating a vertex float attribute to face corners (Ryzen 3700x): **Before** (Average: 3.7 ms, Min: 3.4 ms) ``` threading::parallel_for(loops.index_range(), 4096, [&](IndexRange range) { for (const int64_t i : range) { dst[i] = src[loops[i].v]; } }); ``` **After** (Average: 2.9 ms, Min: 2.6 ms) ``` array_utils::gather(src, corner_verts, dst); ``` That's an improvement of 28% to the average timings, and it's also a simplification, since an index-based routine can be used instead. For more examples using the new arrays, see the design task. Pull Request: https://projects.blender.org/blender/blender/pulls/104424
2023-03-20 15:55:13 +01:00
const Span<int> corner_edges = mesh.corner_edges();
bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
const VArray<bool> uv_seams = *attributes.lookup_or_default<bool>(
"uv_seam", bke::AttrDomain::Edge, false);
bke::SpanAttributeWriter<bool> select_poly = attributes.lookup_or_add_for_write_span<bool>(
".select_poly", bke::AttrDomain::Face);
Set<int> selected_roots;
for (const int i : face_indices) {
for (const int edge : corner_edges.slice(faces[i])) {
Mesh: Replace MLoop struct with generic attributes Implements #102359. Split the `MLoop` struct into two separate integer arrays called `corner_verts` and `corner_edges`, referring to the vertex each corner is attached to and the next edge around the face at each corner. These arrays can be sliced to give access to the edges or vertices in a face. Then they are often referred to as "poly_verts" or "poly_edges". The main benefits are halving the necessary memory bandwidth when only one array is used and simplifications from using regular integer indices instead of a special-purpose struct. The commit also starts a renaming from "loop" to "corner" in mesh code. Like the other mesh struct of array refactors, forward compatibility is kept by writing files with the older format. This will be done until 4.0 to ease the transition process. Looking at a small portion of the patch should give a good impression for the rest of the changes. I tried to make the changes as small as possible so it's easy to tell the correctness from the diff. Though I found Blender developers have been very inventive over the last decade when finding different ways to loop over the corners in a face. For performance, nearly every piece of code that deals with `Mesh` is slightly impacted. Any algorithm that is memory bottle-necked should see an improvement. For example, here is a comparison of interpolating a vertex float attribute to face corners (Ryzen 3700x): **Before** (Average: 3.7 ms, Min: 3.4 ms) ``` threading::parallel_for(loops.index_range(), 4096, [&](IndexRange range) { for (const int64_t i : range) { dst[i] = src[loops[i].v]; } }); ``` **After** (Average: 2.9 ms, Min: 2.6 ms) ``` array_utils::gather(src, corner_verts, dst); ``` That's an improvement of 28% to the average timings, and it's also a simplification, since an index-based routine can be used instead. For more examples using the new arrays, see the design task. Pull Request: https://projects.blender.org/blender/blender/pulls/104424
2023-03-20 15:55:13 +01:00
if (uv_seams[edge]) {
continue;
}
Mesh: Replace MLoop struct with generic attributes Implements #102359. Split the `MLoop` struct into two separate integer arrays called `corner_verts` and `corner_edges`, referring to the vertex each corner is attached to and the next edge around the face at each corner. These arrays can be sliced to give access to the edges or vertices in a face. Then they are often referred to as "poly_verts" or "poly_edges". The main benefits are halving the necessary memory bandwidth when only one array is used and simplifications from using regular integer indices instead of a special-purpose struct. The commit also starts a renaming from "loop" to "corner" in mesh code. Like the other mesh struct of array refactors, forward compatibility is kept by writing files with the older format. This will be done until 4.0 to ease the transition process. Looking at a small portion of the patch should give a good impression for the rest of the changes. I tried to make the changes as small as possible so it's easy to tell the correctness from the diff. Though I found Blender developers have been very inventive over the last decade when finding different ways to loop over the corners in a face. For performance, nearly every piece of code that deals with `Mesh` is slightly impacted. Any algorithm that is memory bottle-necked should see an improvement. For example, here is a comparison of interpolating a vertex float attribute to face corners (Ryzen 3700x): **Before** (Average: 3.7 ms, Min: 3.4 ms) ``` threading::parallel_for(loops.index_range(), 4096, [&](IndexRange range) { for (const int64_t i : range) { dst[i] = src[loops[i].v]; } }); ``` **After** (Average: 2.9 ms, Min: 2.6 ms) ``` array_utils::gather(src, corner_verts, dst); ``` That's an improvement of 28% to the average timings, and it's also a simplification, since an index-based routine can be used instead. For more examples using the new arrays, see the design task. Pull Request: https://projects.blender.org/blender/blender/pulls/104424
2023-03-20 15:55:13 +01:00
const int root = islands.find_root(edge);
selected_roots.add(root);
}
}
threading::parallel_for(select_poly.span.index_range(), 1024, [&](const IndexRange range) {
for (const int face_index : range) {
for (const int edge : corner_edges.slice(faces[face_index])) {
Mesh: Replace MLoop struct with generic attributes Implements #102359. Split the `MLoop` struct into two separate integer arrays called `corner_verts` and `corner_edges`, referring to the vertex each corner is attached to and the next edge around the face at each corner. These arrays can be sliced to give access to the edges or vertices in a face. Then they are often referred to as "poly_verts" or "poly_edges". The main benefits are halving the necessary memory bandwidth when only one array is used and simplifications from using regular integer indices instead of a special-purpose struct. The commit also starts a renaming from "loop" to "corner" in mesh code. Like the other mesh struct of array refactors, forward compatibility is kept by writing files with the older format. This will be done until 4.0 to ease the transition process. Looking at a small portion of the patch should give a good impression for the rest of the changes. I tried to make the changes as small as possible so it's easy to tell the correctness from the diff. Though I found Blender developers have been very inventive over the last decade when finding different ways to loop over the corners in a face. For performance, nearly every piece of code that deals with `Mesh` is slightly impacted. Any algorithm that is memory bottle-necked should see an improvement. For example, here is a comparison of interpolating a vertex float attribute to face corners (Ryzen 3700x): **Before** (Average: 3.7 ms, Min: 3.4 ms) ``` threading::parallel_for(loops.index_range(), 4096, [&](IndexRange range) { for (const int64_t i : range) { dst[i] = src[loops[i].v]; } }); ``` **After** (Average: 2.9 ms, Min: 2.6 ms) ``` array_utils::gather(src, corner_verts, dst); ``` That's an improvement of 28% to the average timings, and it's also a simplification, since an index-based routine can be used instead. For more examples using the new arrays, see the design task. Pull Request: https://projects.blender.org/blender/blender/pulls/104424
2023-03-20 15:55:13 +01:00
const int root = islands.find_root(edge);
if (selected_roots.contains(root)) {
select_poly.span[face_index] = select;
break;
}
}
}
});
select_poly.finish();
}
void paintface_select_linked(bContext *C, Object *ob, const int mval[2], const bool select)
{
using namespace blender;
Mesh *mesh = BKE_mesh_from_object(ob);
if (mesh == nullptr || mesh->faces_num == 0) {
return;
2019-04-22 09:19:45 +10:00
}
bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
bke::SpanAttributeWriter<bool> select_poly = attributes.lookup_or_add_for_write_span<bool>(
".select_poly", bke::AttrDomain::Face);
Vector<int> indices;
if (mval) {
uint index = uint(-1);
2019-03-16 11:38:55 +11:00
if (!ED_mesh_pick_face(C, ob, mval, ED_MESH_PICK_DEFAULT_FACE_DIST, &index)) {
select_poly.finish();
return;
}
/* Since paintface_select_linked_faces might not select the face under the cursor, select it
* here. */
select_poly.span[index] = true;
indices.append(index);
}
else {
for (const int i : select_poly.span.index_range()) {
if (!select_poly.span[i]) {
continue;
}
indices.append(i);
}
}
select_poly.finish();
paintface_select_linked_faces(*mesh, indices, select);
paintface_flush_flags(C, ob, true, false);
}
static int get_opposing_edge_index(const blender::IndexRange face,
const blender::Span<int> corner_edges,
const int current_edge_index)
{
const int index_in_poly = corner_edges.slice(face).first_index(current_edge_index);
/* Assumes that edge index of opposing face edge is always off by 2 on quads. */
if (index_in_poly >= 2) {
return corner_edges[face[index_in_poly - 2]];
}
/* Cannot be out of bounds because of the preceding if statement: if i < 2 then i+2 < 4. */
return corner_edges[face[index_in_poly + 2]];
}
/**
* Follow quads around the mesh by finding opposing edges.
* \return True if the search has looped back on itself, finding the same index twice.
*/
static bool follow_face_loop(const int face_start_index,
const int edge_start_index,
const blender::OffsetIndices<int> faces,
const blender::VArray<bool> &hide_poly,
const blender::Span<int> corner_edges,
const blender::GroupedSpan<int> edge_to_face_map,
blender::VectorSet<int> &r_loop_faces)
{
using namespace blender;
int current_face_index = face_start_index;
int current_edge_index = edge_start_index;
while (current_edge_index > 0) {
int next_face_index = -1;
for (const int face_index : edge_to_face_map[current_edge_index]) {
if (face_index != current_face_index) {
next_face_index = face_index;
break;
}
}
/* Edge might only have 1 face connected. */
if (next_face_index == -1) {
return false;
}
/* Only works on quads. */
if (faces[next_face_index].size() != 4) {
return false;
}
/* Happens if we looped around the mesh. */
if (r_loop_faces.contains(next_face_index)) {
return true;
}
/* Hidden faces stop selection. */
if (hide_poly[next_face_index]) {
return false;
}
r_loop_faces.add(next_face_index);
const IndexRange next_face = faces[next_face_index];
current_edge_index = get_opposing_edge_index(next_face, corner_edges, current_edge_index);
current_face_index = next_face_index;
}
return false;
}
void paintface_select_loop(bContext *C, Object *ob, const int mval[2], const bool select)
{
using namespace blender;
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc = ED_view3d_viewcontext_init(C, depsgraph);
ED_view3d_select_id_validate(&vc);
Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
if (!ob_eval) {
return;
}
uint closest_edge_index = uint(-1);
if (!ED_mesh_pick_edge(C, ob, mval, ED_MESH_PICK_DEFAULT_VERT_DIST, &closest_edge_index)) {
return;
}
if (closest_edge_index == -1) {
return;
}
ARegion *region = CTX_wm_region(C);
RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
ED_view3d_init_mats_rv3d(ob_eval, rv3d);
Mesh *mesh = BKE_mesh_from_object(ob);
const Span<int> corner_edges = mesh->corner_edges();
const OffsetIndices faces = mesh->faces();
Array<int> edge_to_face_offsets;
Array<int> edge_to_face_indices;
const GroupedSpan<int> edge_to_face_map = bke::mesh::build_edge_to_face_map(
faces, corner_edges, mesh->edges_num, edge_to_face_offsets, edge_to_face_indices);
VectorSet<int> faces_to_select;
bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
const VArray<bool> hide_poly = *attributes.lookup_or_default<bool>(
".hide_poly", bke::AttrDomain::Face, false);
const Span<int> faces_to_closest_edge = edge_to_face_map[closest_edge_index];
/* Picked edge may not be linked to a face (loose edge). */
if (faces_to_closest_edge.is_empty()) {
return;
}
const bool traced_full_loop = follow_face_loop(faces_to_closest_edge[0],
closest_edge_index,
faces,
hide_poly,
corner_edges,
edge_to_face_map,
faces_to_select);
if (!traced_full_loop && faces_to_closest_edge.size() > 1) {
/* Trace the other way. */
follow_face_loop(faces_to_closest_edge[1],
closest_edge_index,
faces,
hide_poly,
corner_edges,
edge_to_face_map,
faces_to_select);
}
bke::SpanAttributeWriter<bool> select_poly = attributes.lookup_or_add_for_write_span<bool>(
".select_poly", bke::AttrDomain::Face);
/* Toggling behavior. When one of the faces of the picked edge is already selected,
* it deselects the loop instead. */
bool any_adjacent_poly_selected = false;
for (const int i : faces_to_closest_edge) {
any_adjacent_poly_selected |= select_poly.span[i];
}
const bool select_toggle = select && !any_adjacent_poly_selected;
select_poly.span.fill_indices(faces_to_select.as_span(), select_toggle);
select_poly.finish();
paintface_flush_flags(C, ob, true, false);
}
static bool poly_has_selected_neighbor(blender::Span<int> face_edges,
Mesh: Move edges to a generic attribute Implements #95966, as the final step of #95965. This commit changes the storage of mesh edge vertex indices from the `MEdge` type to the generic `int2` attribute type. This follows the general design for geometry and the attribute system, where the data storage type and the usage semantics are separated. The main benefit of the change is reduced memory usage-- the requirements of storing mesh edges is reduced by 1/3. For example, this saves 8MB on a 1 million vertex grid. This also gives performance benefits to any memory-bound mesh processing algorithm that uses edges. Another benefit is that all of the edge's vertex indices are contiguous. In a few cases, it's helpful to process all of them as `Span<int>` rather than `Span<int2>`. Similarly, the type is more likely to match a generic format used by a library, or code that shouldn't know about specific Blender `Mesh` types. Various Notes: - The `.edge_verts` name is used to reflect a mapping between domains, similar to `.corner_verts`, etc. The period means that it the data shouldn't change arbitrarily by the user or procedural operations. - `edge[0]` is now used instead of `edge.v1` - Signed integers are used instead of unsigned to reduce the mixing of signed-ness, which can be error prone. - All of the previously used core mesh data types (`MVert`, `MEdge`, `MLoop`, `MPoly` are now deprecated. Only generic types are used). - The `vec2i` DNA type is used in the few C files where necessary. Pull Request: https://projects.blender.org/blender/blender/pulls/106638
2023-04-17 13:47:41 +02:00
blender::Span<blender::int2> edges,
blender::Span<bool> select_vert,
const bool face_step)
{
for (const int edge_index : face_edges) {
Mesh: Move edges to a generic attribute Implements #95966, as the final step of #95965. This commit changes the storage of mesh edge vertex indices from the `MEdge` type to the generic `int2` attribute type. This follows the general design for geometry and the attribute system, where the data storage type and the usage semantics are separated. The main benefit of the change is reduced memory usage-- the requirements of storing mesh edges is reduced by 1/3. For example, this saves 8MB on a 1 million vertex grid. This also gives performance benefits to any memory-bound mesh processing algorithm that uses edges. Another benefit is that all of the edge's vertex indices are contiguous. In a few cases, it's helpful to process all of them as `Span<int>` rather than `Span<int2>`. Similarly, the type is more likely to match a generic format used by a library, or code that shouldn't know about specific Blender `Mesh` types. Various Notes: - The `.edge_verts` name is used to reflect a mapping between domains, similar to `.corner_verts`, etc. The period means that it the data shouldn't change arbitrarily by the user or procedural operations. - `edge[0]` is now used instead of `edge.v1` - Signed integers are used instead of unsigned to reduce the mixing of signed-ness, which can be error prone. - All of the previously used core mesh data types (`MVert`, `MEdge`, `MLoop`, `MPoly` are now deprecated. Only generic types are used). - The `vec2i` DNA type is used in the few C files where necessary. Pull Request: https://projects.blender.org/blender/blender/pulls/106638
2023-04-17 13:47:41 +02:00
const blender::int2 &edge = edges[edge_index];
/* If a face is selected, all of its verts are selected too, meaning that neighboring faces
* will have some vertices selected. */
if (face_step) {
Mesh: Move edges to a generic attribute Implements #95966, as the final step of #95965. This commit changes the storage of mesh edge vertex indices from the `MEdge` type to the generic `int2` attribute type. This follows the general design for geometry and the attribute system, where the data storage type and the usage semantics are separated. The main benefit of the change is reduced memory usage-- the requirements of storing mesh edges is reduced by 1/3. For example, this saves 8MB on a 1 million vertex grid. This also gives performance benefits to any memory-bound mesh processing algorithm that uses edges. Another benefit is that all of the edge's vertex indices are contiguous. In a few cases, it's helpful to process all of them as `Span<int>` rather than `Span<int2>`. Similarly, the type is more likely to match a generic format used by a library, or code that shouldn't know about specific Blender `Mesh` types. Various Notes: - The `.edge_verts` name is used to reflect a mapping between domains, similar to `.corner_verts`, etc. The period means that it the data shouldn't change arbitrarily by the user or procedural operations. - `edge[0]` is now used instead of `edge.v1` - Signed integers are used instead of unsigned to reduce the mixing of signed-ness, which can be error prone. - All of the previously used core mesh data types (`MVert`, `MEdge`, `MLoop`, `MPoly` are now deprecated. Only generic types are used). - The `vec2i` DNA type is used in the few C files where necessary. Pull Request: https://projects.blender.org/blender/blender/pulls/106638
2023-04-17 13:47:41 +02:00
if (select_vert[edge[0]] || select_vert[edge[1]]) {
return true;
}
}
else {
Mesh: Move edges to a generic attribute Implements #95966, as the final step of #95965. This commit changes the storage of mesh edge vertex indices from the `MEdge` type to the generic `int2` attribute type. This follows the general design for geometry and the attribute system, where the data storage type and the usage semantics are separated. The main benefit of the change is reduced memory usage-- the requirements of storing mesh edges is reduced by 1/3. For example, this saves 8MB on a 1 million vertex grid. This also gives performance benefits to any memory-bound mesh processing algorithm that uses edges. Another benefit is that all of the edge's vertex indices are contiguous. In a few cases, it's helpful to process all of them as `Span<int>` rather than `Span<int2>`. Similarly, the type is more likely to match a generic format used by a library, or code that shouldn't know about specific Blender `Mesh` types. Various Notes: - The `.edge_verts` name is used to reflect a mapping between domains, similar to `.corner_verts`, etc. The period means that it the data shouldn't change arbitrarily by the user or procedural operations. - `edge[0]` is now used instead of `edge.v1` - Signed integers are used instead of unsigned to reduce the mixing of signed-ness, which can be error prone. - All of the previously used core mesh data types (`MVert`, `MEdge`, `MLoop`, `MPoly` are now deprecated. Only generic types are used). - The `vec2i` DNA type is used in the few C files where necessary. Pull Request: https://projects.blender.org/blender/blender/pulls/106638
2023-04-17 13:47:41 +02:00
if (select_vert[edge[0]] && select_vert[edge[1]]) {
return true;
}
}
}
return false;
}
void paintface_select_more(Mesh *mesh, const bool face_step)
{
using namespace blender;
bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
bke::SpanAttributeWriter<bool> select_poly = attributes.lookup_or_add_for_write_span<bool>(
".select_poly", bke::AttrDomain::Face);
bke::SpanAttributeWriter<bool> select_vert = attributes.lookup_or_add_for_write_span<bool>(
".select_vert", bke::AttrDomain::Point);
const VArray<bool> hide_poly = *attributes.lookup_or_default<bool>(
".hide_poly", bke::AttrDomain::Face, false);
const OffsetIndices faces = mesh->faces();
const Span<int> corner_edges = mesh->corner_edges();
Mesh: Move edges to a generic attribute Implements #95966, as the final step of #95965. This commit changes the storage of mesh edge vertex indices from the `MEdge` type to the generic `int2` attribute type. This follows the general design for geometry and the attribute system, where the data storage type and the usage semantics are separated. The main benefit of the change is reduced memory usage-- the requirements of storing mesh edges is reduced by 1/3. For example, this saves 8MB on a 1 million vertex grid. This also gives performance benefits to any memory-bound mesh processing algorithm that uses edges. Another benefit is that all of the edge's vertex indices are contiguous. In a few cases, it's helpful to process all of them as `Span<int>` rather than `Span<int2>`. Similarly, the type is more likely to match a generic format used by a library, or code that shouldn't know about specific Blender `Mesh` types. Various Notes: - The `.edge_verts` name is used to reflect a mapping between domains, similar to `.corner_verts`, etc. The period means that it the data shouldn't change arbitrarily by the user or procedural operations. - `edge[0]` is now used instead of `edge.v1` - Signed integers are used instead of unsigned to reduce the mixing of signed-ness, which can be error prone. - All of the previously used core mesh data types (`MVert`, `MEdge`, `MLoop`, `MPoly` are now deprecated. Only generic types are used). - The `vec2i` DNA type is used in the few C files where necessary. Pull Request: https://projects.blender.org/blender/blender/pulls/106638
2023-04-17 13:47:41 +02:00
const Span<int2> edges = mesh->edges();
threading::parallel_for(select_poly.span.index_range(), 1024, [&](const IndexRange range) {
for (const int i : range) {
if (select_poly.span[i] || hide_poly[i]) {
continue;
}
const IndexRange face = faces[i];
if (poly_has_selected_neighbor(corner_edges.slice(face), edges, select_vert.span, face_step))
Mesh: Replace MPoly struct with offset indices Implements #95967. Currently the `MPoly` struct is 12 bytes, and stores the index of a face's first corner and the number of corners/verts/edges. Polygons and corners are always created in order by Blender, meaning each face's corners will be after the previous face's corners. We can take advantage of this fact and eliminate the redundancy in mesh face storage by only storing a single integer corner offset for each face. The size of the face is then encoded by the offset of the next face. The size of a single integer is 4 bytes, so this reduces memory usage by 3 times. The same method is used for `CurvesGeometry`, so Blender already has an abstraction to simplify using these offsets called `OffsetIndices`. This class is used to easily retrieve a range of corner indices for each face. This also gives the opportunity for sharing some logic with curves. Another benefit of the change is that the offsets and sizes stored in `MPoly` can no longer disagree with each other. Storing faces in the order of their corners can simplify some code too. Face/polygon variables now use the `IndexRange` type, which comes with quite a few utilities that can simplify code. Some: - The offset integer array has to be one longer than the face count to avoid a branch for every face, which means the data is no longer part of the mesh's `CustomData`. - We lose the ability to "reference" an original mesh's offset array until more reusable CoW from #104478 is committed. That will be added in a separate commit. - Since they aren't part of `CustomData`, poly offsets often have to be copied manually. - To simplify using `OffsetIndices` in many places, some functions and structs in headers were moved to only compile in C++. - All meshes created by Blender use the same order for faces and face corners, but just in case, meshes with mismatched order are fixed by versioning code. - `MeshPolygon.totloop` is no longer editable in RNA. This API break is necessary here unfortunately. It should be worth it in 3.6, since that's the best way to allow loading meshes from 4.0, which is important for an LTS version. Pull Request: https://projects.blender.org/blender/blender/pulls/105938
2023-04-04 20:39:28 +02:00
{
select_poly.span[i] = true;
}
}
});
select_poly.finish();
select_vert.finish();
}
static bool poly_has_unselected_neighbor(blender::Span<int> face_edges,
Mesh: Move edges to a generic attribute Implements #95966, as the final step of #95965. This commit changes the storage of mesh edge vertex indices from the `MEdge` type to the generic `int2` attribute type. This follows the general design for geometry and the attribute system, where the data storage type and the usage semantics are separated. The main benefit of the change is reduced memory usage-- the requirements of storing mesh edges is reduced by 1/3. For example, this saves 8MB on a 1 million vertex grid. This also gives performance benefits to any memory-bound mesh processing algorithm that uses edges. Another benefit is that all of the edge's vertex indices are contiguous. In a few cases, it's helpful to process all of them as `Span<int>` rather than `Span<int2>`. Similarly, the type is more likely to match a generic format used by a library, or code that shouldn't know about specific Blender `Mesh` types. Various Notes: - The `.edge_verts` name is used to reflect a mapping between domains, similar to `.corner_verts`, etc. The period means that it the data shouldn't change arbitrarily by the user or procedural operations. - `edge[0]` is now used instead of `edge.v1` - Signed integers are used instead of unsigned to reduce the mixing of signed-ness, which can be error prone. - All of the previously used core mesh data types (`MVert`, `MEdge`, `MLoop`, `MPoly` are now deprecated. Only generic types are used). - The `vec2i` DNA type is used in the few C files where necessary. Pull Request: https://projects.blender.org/blender/blender/pulls/106638
2023-04-17 13:47:41 +02:00
blender::Span<blender::int2> edges,
blender::BitSpan verts_of_unselected_faces,
const bool face_step)
{
for (const int edge_index : face_edges) {
Mesh: Move edges to a generic attribute Implements #95966, as the final step of #95965. This commit changes the storage of mesh edge vertex indices from the `MEdge` type to the generic `int2` attribute type. This follows the general design for geometry and the attribute system, where the data storage type and the usage semantics are separated. The main benefit of the change is reduced memory usage-- the requirements of storing mesh edges is reduced by 1/3. For example, this saves 8MB on a 1 million vertex grid. This also gives performance benefits to any memory-bound mesh processing algorithm that uses edges. Another benefit is that all of the edge's vertex indices are contiguous. In a few cases, it's helpful to process all of them as `Span<int>` rather than `Span<int2>`. Similarly, the type is more likely to match a generic format used by a library, or code that shouldn't know about specific Blender `Mesh` types. Various Notes: - The `.edge_verts` name is used to reflect a mapping between domains, similar to `.corner_verts`, etc. The period means that it the data shouldn't change arbitrarily by the user or procedural operations. - `edge[0]` is now used instead of `edge.v1` - Signed integers are used instead of unsigned to reduce the mixing of signed-ness, which can be error prone. - All of the previously used core mesh data types (`MVert`, `MEdge`, `MLoop`, `MPoly` are now deprecated. Only generic types are used). - The `vec2i` DNA type is used in the few C files where necessary. Pull Request: https://projects.blender.org/blender/blender/pulls/106638
2023-04-17 13:47:41 +02:00
const blender::int2 &edge = edges[edge_index];
if (face_step) {
Mesh: Move edges to a generic attribute Implements #95966, as the final step of #95965. This commit changes the storage of mesh edge vertex indices from the `MEdge` type to the generic `int2` attribute type. This follows the general design for geometry and the attribute system, where the data storage type and the usage semantics are separated. The main benefit of the change is reduced memory usage-- the requirements of storing mesh edges is reduced by 1/3. For example, this saves 8MB on a 1 million vertex grid. This also gives performance benefits to any memory-bound mesh processing algorithm that uses edges. Another benefit is that all of the edge's vertex indices are contiguous. In a few cases, it's helpful to process all of them as `Span<int>` rather than `Span<int2>`. Similarly, the type is more likely to match a generic format used by a library, or code that shouldn't know about specific Blender `Mesh` types. Various Notes: - The `.edge_verts` name is used to reflect a mapping between domains, similar to `.corner_verts`, etc. The period means that it the data shouldn't change arbitrarily by the user or procedural operations. - `edge[0]` is now used instead of `edge.v1` - Signed integers are used instead of unsigned to reduce the mixing of signed-ness, which can be error prone. - All of the previously used core mesh data types (`MVert`, `MEdge`, `MLoop`, `MPoly` are now deprecated. Only generic types are used). - The `vec2i` DNA type is used in the few C files where necessary. Pull Request: https://projects.blender.org/blender/blender/pulls/106638
2023-04-17 13:47:41 +02:00
if (verts_of_unselected_faces[edge[0]] || verts_of_unselected_faces[edge[1]]) {
return true;
}
}
else {
Mesh: Move edges to a generic attribute Implements #95966, as the final step of #95965. This commit changes the storage of mesh edge vertex indices from the `MEdge` type to the generic `int2` attribute type. This follows the general design for geometry and the attribute system, where the data storage type and the usage semantics are separated. The main benefit of the change is reduced memory usage-- the requirements of storing mesh edges is reduced by 1/3. For example, this saves 8MB on a 1 million vertex grid. This also gives performance benefits to any memory-bound mesh processing algorithm that uses edges. Another benefit is that all of the edge's vertex indices are contiguous. In a few cases, it's helpful to process all of them as `Span<int>` rather than `Span<int2>`. Similarly, the type is more likely to match a generic format used by a library, or code that shouldn't know about specific Blender `Mesh` types. Various Notes: - The `.edge_verts` name is used to reflect a mapping between domains, similar to `.corner_verts`, etc. The period means that it the data shouldn't change arbitrarily by the user or procedural operations. - `edge[0]` is now used instead of `edge.v1` - Signed integers are used instead of unsigned to reduce the mixing of signed-ness, which can be error prone. - All of the previously used core mesh data types (`MVert`, `MEdge`, `MLoop`, `MPoly` are now deprecated. Only generic types are used). - The `vec2i` DNA type is used in the few C files where necessary. Pull Request: https://projects.blender.org/blender/blender/pulls/106638
2023-04-17 13:47:41 +02:00
if (verts_of_unselected_faces[edge[0]] && verts_of_unselected_faces[edge[1]]) {
return true;
}
}
}
return false;
}
void paintface_select_less(Mesh *mesh, const bool face_step)
{
using namespace blender;
bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
bke::SpanAttributeWriter<bool> select_poly = attributes.lookup_or_add_for_write_span<bool>(
".select_poly", bke::AttrDomain::Face);
const VArray<bool> hide_poly = *attributes.lookup_or_default<bool>(
".hide_poly", bke::AttrDomain::Face, false);
const OffsetIndices faces = mesh->faces();
const Span<int> corner_verts = mesh->corner_verts();
const Span<int> corner_edges = mesh->corner_edges();
Mesh: Move edges to a generic attribute Implements #95966, as the final step of #95965. This commit changes the storage of mesh edge vertex indices from the `MEdge` type to the generic `int2` attribute type. This follows the general design for geometry and the attribute system, where the data storage type and the usage semantics are separated. The main benefit of the change is reduced memory usage-- the requirements of storing mesh edges is reduced by 1/3. For example, this saves 8MB on a 1 million vertex grid. This also gives performance benefits to any memory-bound mesh processing algorithm that uses edges. Another benefit is that all of the edge's vertex indices are contiguous. In a few cases, it's helpful to process all of them as `Span<int>` rather than `Span<int2>`. Similarly, the type is more likely to match a generic format used by a library, or code that shouldn't know about specific Blender `Mesh` types. Various Notes: - The `.edge_verts` name is used to reflect a mapping between domains, similar to `.corner_verts`, etc. The period means that it the data shouldn't change arbitrarily by the user or procedural operations. - `edge[0]` is now used instead of `edge.v1` - Signed integers are used instead of unsigned to reduce the mixing of signed-ness, which can be error prone. - All of the previously used core mesh data types (`MVert`, `MEdge`, `MLoop`, `MPoly` are now deprecated. Only generic types are used). - The `vec2i` DNA type is used in the few C files where necessary. Pull Request: https://projects.blender.org/blender/blender/pulls/106638
2023-04-17 13:47:41 +02:00
const Span<int2> edges = mesh->edges();
BitVector<> verts_of_unselected_faces(mesh->verts_num);
/* Find all vertices of unselected faces to help find neighboring faces after. */
for (const int i : faces.index_range()) {
if (select_poly.span[i]) {
continue;
}
const IndexRange face = faces[i];
for (const int vert : corner_verts.slice(face)) {
verts_of_unselected_faces[vert].set(true);
}
}
threading::parallel_for(faces.index_range(), 1024, [&](const IndexRange range) {
for (const int i : range) {
if (!select_poly.span[i] || hide_poly[i]) {
continue;
}
const IndexRange face = faces[i];
Mesh: Replace MPoly struct with offset indices Implements #95967. Currently the `MPoly` struct is 12 bytes, and stores the index of a face's first corner and the number of corners/verts/edges. Polygons and corners are always created in order by Blender, meaning each face's corners will be after the previous face's corners. We can take advantage of this fact and eliminate the redundancy in mesh face storage by only storing a single integer corner offset for each face. The size of the face is then encoded by the offset of the next face. The size of a single integer is 4 bytes, so this reduces memory usage by 3 times. The same method is used for `CurvesGeometry`, so Blender already has an abstraction to simplify using these offsets called `OffsetIndices`. This class is used to easily retrieve a range of corner indices for each face. This also gives the opportunity for sharing some logic with curves. Another benefit of the change is that the offsets and sizes stored in `MPoly` can no longer disagree with each other. Storing faces in the order of their corners can simplify some code too. Face/polygon variables now use the `IndexRange` type, which comes with quite a few utilities that can simplify code. Some: - The offset integer array has to be one longer than the face count to avoid a branch for every face, which means the data is no longer part of the mesh's `CustomData`. - We lose the ability to "reference" an original mesh's offset array until more reusable CoW from #104478 is committed. That will be added in a separate commit. - Since they aren't part of `CustomData`, poly offsets often have to be copied manually. - To simplify using `OffsetIndices` in many places, some functions and structs in headers were moved to only compile in C++. - All meshes created by Blender use the same order for faces and face corners, but just in case, meshes with mismatched order are fixed by versioning code. - `MeshPolygon.totloop` is no longer editable in RNA. This API break is necessary here unfortunately. It should be worth it in 3.6, since that's the best way to allow loading meshes from 4.0, which is important for an LTS version. Pull Request: https://projects.blender.org/blender/blender/pulls/105938
2023-04-04 20:39:28 +02:00
if (poly_has_unselected_neighbor(
corner_edges.slice(face), edges, verts_of_unselected_faces, face_step))
Mesh: Replace MPoly struct with offset indices Implements #95967. Currently the `MPoly` struct is 12 bytes, and stores the index of a face's first corner and the number of corners/verts/edges. Polygons and corners are always created in order by Blender, meaning each face's corners will be after the previous face's corners. We can take advantage of this fact and eliminate the redundancy in mesh face storage by only storing a single integer corner offset for each face. The size of the face is then encoded by the offset of the next face. The size of a single integer is 4 bytes, so this reduces memory usage by 3 times. The same method is used for `CurvesGeometry`, so Blender already has an abstraction to simplify using these offsets called `OffsetIndices`. This class is used to easily retrieve a range of corner indices for each face. This also gives the opportunity for sharing some logic with curves. Another benefit of the change is that the offsets and sizes stored in `MPoly` can no longer disagree with each other. Storing faces in the order of their corners can simplify some code too. Face/polygon variables now use the `IndexRange` type, which comes with quite a few utilities that can simplify code. Some: - The offset integer array has to be one longer than the face count to avoid a branch for every face, which means the data is no longer part of the mesh's `CustomData`. - We lose the ability to "reference" an original mesh's offset array until more reusable CoW from #104478 is committed. That will be added in a separate commit. - Since they aren't part of `CustomData`, poly offsets often have to be copied manually. - To simplify using `OffsetIndices` in many places, some functions and structs in headers were moved to only compile in C++. - All meshes created by Blender use the same order for faces and face corners, but just in case, meshes with mismatched order are fixed by versioning code. - `MeshPolygon.totloop` is no longer editable in RNA. This API break is necessary here unfortunately. It should be worth it in 3.6, since that's the best way to allow loading meshes from 4.0, which is important for an LTS version. Pull Request: https://projects.blender.org/blender/blender/pulls/105938
2023-04-04 20:39:28 +02:00
{
select_poly.span[i] = false;
}
}
});
select_poly.finish();
}
bool paintface_deselect_all_visible(bContext *C, Object *ob, int action, bool flush_flags)
{
using namespace blender;
Mesh *mesh = BKE_mesh_from_object(ob);
if (mesh == nullptr) {
return false;
}
bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
const VArray<bool> hide_poly = *attributes.lookup_or_default<bool>(
".hide_poly", bke::AttrDomain::Face, false);
2022-09-23 09:38:37 -05:00
bke::SpanAttributeWriter<bool> select_poly = attributes.lookup_or_add_for_write_span<bool>(
".select_poly", bke::AttrDomain::Face);
2013-08-03 16:55:49 +00:00
if (action == SEL_TOGGLE) {
action = SEL_SELECT;
for (int i = 0; i < mesh->faces_num; i++) {
2022-09-23 09:38:37 -05:00
if (!hide_poly[i] && select_poly.span[i]) {
2013-08-03 16:55:49 +00:00
action = SEL_DESELECT;
break;
}
}
}
bool changed = false;
for (int i = 0; i < mesh->faces_num; i++) {
2022-09-23 09:38:37 -05:00
if (hide_poly[i]) {
continue;
}
const bool old_selection = select_poly.span[i];
switch (action) {
case SEL_SELECT:
select_poly.span[i] = true;
break;
case SEL_DESELECT:
select_poly.span[i] = false;
break;
case SEL_INVERT:
select_poly.span[i] = !select_poly.span[i];
changed = true;
break;
}
if (old_selection != select_poly.span[i]) {
changed = true;
}
}
2022-09-23 09:38:37 -05:00
select_poly.finish();
if (changed) {
if (flush_flags) {
paintface_flush_flags(C, ob, true, false);
}
}
return changed;
}
bool paintface_minmax(Object *ob, float r_min[3], float r_max[3])
{
using namespace blender;
bool ok = false;
float vec[3], bmat[3][3];
const Mesh *mesh = BKE_mesh_from_object(ob);
if (!mesh || !CustomData_has_layer(&mesh->corner_data, CD_PROP_FLOAT2)) {
return ok;
}
copy_m3_m4(bmat, ob->object_to_world().ptr());
const Span<float3> positions = mesh->vert_positions();
const OffsetIndices faces = mesh->faces();
const Span<int> corner_verts = mesh->corner_verts();
bke::AttributeAccessor attributes = mesh->attributes();
const VArray<bool> hide_poly = *attributes.lookup_or_default<bool>(
".hide_poly", bke::AttrDomain::Face, false);
const VArray<bool> select_poly = *attributes.lookup_or_default<bool>(
".select_poly", bke::AttrDomain::Face, false);
for (int i = 0; i < mesh->faces_num; i++) {
2022-09-23 09:38:37 -05:00
if (hide_poly[i] || !select_poly[i]) {
continue;
2019-04-22 09:19:45 +10:00
}
for (const int vert : corner_verts.slice(faces[i])) {
Mesh: Replace MPoly struct with offset indices Implements #95967. Currently the `MPoly` struct is 12 bytes, and stores the index of a face's first corner and the number of corners/verts/edges. Polygons and corners are always created in order by Blender, meaning each face's corners will be after the previous face's corners. We can take advantage of this fact and eliminate the redundancy in mesh face storage by only storing a single integer corner offset for each face. The size of the face is then encoded by the offset of the next face. The size of a single integer is 4 bytes, so this reduces memory usage by 3 times. The same method is used for `CurvesGeometry`, so Blender already has an abstraction to simplify using these offsets called `OffsetIndices`. This class is used to easily retrieve a range of corner indices for each face. This also gives the opportunity for sharing some logic with curves. Another benefit of the change is that the offsets and sizes stored in `MPoly` can no longer disagree with each other. Storing faces in the order of their corners can simplify some code too. Face/polygon variables now use the `IndexRange` type, which comes with quite a few utilities that can simplify code. Some: - The offset integer array has to be one longer than the face count to avoid a branch for every face, which means the data is no longer part of the mesh's `CustomData`. - We lose the ability to "reference" an original mesh's offset array until more reusable CoW from #104478 is committed. That will be added in a separate commit. - Since they aren't part of `CustomData`, poly offsets often have to be copied manually. - To simplify using `OffsetIndices` in many places, some functions and structs in headers were moved to only compile in C++. - All meshes created by Blender use the same order for faces and face corners, but just in case, meshes with mismatched order are fixed by versioning code. - `MeshPolygon.totloop` is no longer editable in RNA. This API break is necessary here unfortunately. It should be worth it in 3.6, since that's the best way to allow loading meshes from 4.0, which is important for an LTS version. Pull Request: https://projects.blender.org/blender/blender/pulls/105938
2023-04-04 20:39:28 +02:00
mul_v3_m3v3(vec, bmat, positions[vert]);
add_v3_v3v3(vec, vec, ob->object_to_world().location());
minmax_v3v3_v3(r_min, r_max, vec);
}
ok = true;
}
return ok;
}
bool paintface_mouse_select(bContext *C,
const int mval[2],
const SelectPick_Params *params,
Object *ob)
{
using namespace blender;
2019-03-27 13:19:02 +11:00
uint index;
bool changed = false;
bool found = false;
/* Get the face under the cursor */
Mesh *mesh = BKE_mesh_from_object(ob);
bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
const VArray<bool> hide_poly = *attributes.lookup_or_default<bool>(
".hide_poly", bke::AttrDomain::Face, false);
2022-09-23 09:38:37 -05:00
bke::AttributeWriter<bool> select_poly = attributes.lookup_or_add_for_write<bool>(
".select_poly", bke::AttrDomain::Face);
if (ED_mesh_pick_face(C, ob, mval, ED_MESH_PICK_DEFAULT_FACE_DIST, &index)) {
if (index < mesh->faces_num) {
if (!hide_poly[index]) {
found = true;
}
}
2019-04-22 09:19:45 +10:00
}
if (params->sel_op == SEL_OP_SET) {
2022-09-23 09:38:37 -05:00
if ((found && params->select_passthrough) && select_poly.varray[index]) {
found = false;
}
else if (found || params->deselect_all) {
/* Deselect everything. */
changed |= paintface_deselect_all_visible(C, ob, SEL_DESELECT, false);
}
}
if (found) {
mesh->act_face = int(index);
switch (params->sel_op) {
2022-09-23 09:38:37 -05:00
case SEL_OP_SET:
case SEL_OP_ADD:
select_poly.varray.set(index, true);
break;
2022-09-23 09:38:37 -05:00
case SEL_OP_SUB:
select_poly.varray.set(index, false);
break;
2022-09-23 09:38:37 -05:00
case SEL_OP_XOR:
select_poly.varray.set(index, !select_poly.varray[index]);
break;
2022-09-23 09:38:37 -05:00
case SEL_OP_AND:
BLI_assert_unreachable(); /* Doesn't make sense for picking. */
break;
2019-04-22 09:19:45 +10:00
}
/* image window redraw */
paintface_flush_flags(C, ob, true, false);
ED_region_tag_redraw(CTX_wm_region(C)); /* XXX: should redraw all 3D views. */
changed = true;
}
select_poly.finish();
return changed || found;
}
void paintvert_flush_flags(Object *ob)
{
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
2022-09-05 11:56:34 -05:00
using namespace blender;
Mesh *mesh = BKE_mesh_from_object(ob);
Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
if (mesh == nullptr) {
return;
2019-04-22 09:19:45 +10:00
}
/* we could call this directly in all areas that change selection,
* since this could become slow for realtime updates (circle-select for eg) */
bke::mesh_select_vert_flush(*mesh);
if (mesh_eval == nullptr) {
return;
2019-04-22 09:19:45 +10:00
}
const bke::AttributeAccessor attributes_orig = mesh->attributes();
bke::MutableAttributeAccessor attributes_eval = mesh_eval->attributes_for_write();
const int *orig_indices = (const int *)CustomData_get_layer(&mesh_eval->vert_data, CD_ORIGINDEX);
const VArray<bool> hide_vert_orig = *attributes_orig.lookup_or_default<bool>(
".hide_vert", bke::AttrDomain::Point, false);
2022-09-23 09:38:37 -05:00
bke::SpanAttributeWriter<bool> hide_vert_eval =
attributes_eval.lookup_or_add_for_write_only_span<bool>(".hide_vert",
bke::AttrDomain::Point);
2022-09-23 09:38:37 -05:00
if (orig_indices) {
for (const int i : hide_vert_eval.span.index_range()) {
if (orig_indices[i] != ORIGINDEX_NONE) {
hide_vert_eval.span[i] = hide_vert_orig[orig_indices[i]];
}
}
}
else {
2022-09-23 09:38:37 -05:00
hide_vert_orig.materialize(hide_vert_eval.span);
}
hide_vert_eval.finish();
const VArray<bool> select_vert_orig = *attributes_orig.lookup_or_default<bool>(
".select_vert", bke::AttrDomain::Point, false);
2022-09-23 09:38:37 -05:00
bke::SpanAttributeWriter<bool> select_vert_eval =
attributes_eval.lookup_or_add_for_write_only_span<bool>(".select_vert",
bke::AttrDomain::Point);
2022-09-23 09:38:37 -05:00
if (orig_indices) {
for (const int i : select_vert_eval.span.index_range()) {
if (orig_indices[i] != ORIGINDEX_NONE) {
select_vert_eval.span[i] = select_vert_orig[orig_indices[i]];
}
}
}
2022-09-23 09:38:37 -05:00
else {
select_vert_orig.materialize(select_vert_eval.span);
}
select_vert_eval.finish();
BKE_mesh_batch_cache_dirty_tag(mesh, BKE_MESH_BATCH_DIRTY_ALL);
}
static void paintvert_select_linked_vertices(bContext *C,
Object *ob,
const blender::Span<int> vertex_indices,
const bool select)
{
using namespace blender;
Mesh *mesh = BKE_mesh_from_object(ob);
if (mesh == nullptr || mesh->faces_num == 0) {
return;
}
/* AtomicDisjointSet is used to store connection information in vertex indices. */
AtomicDisjointSet islands(mesh->verts_num);
Mesh: Move edges to a generic attribute Implements #95966, as the final step of #95965. This commit changes the storage of mesh edge vertex indices from the `MEdge` type to the generic `int2` attribute type. This follows the general design for geometry and the attribute system, where the data storage type and the usage semantics are separated. The main benefit of the change is reduced memory usage-- the requirements of storing mesh edges is reduced by 1/3. For example, this saves 8MB on a 1 million vertex grid. This also gives performance benefits to any memory-bound mesh processing algorithm that uses edges. Another benefit is that all of the edge's vertex indices are contiguous. In a few cases, it's helpful to process all of them as `Span<int>` rather than `Span<int2>`. Similarly, the type is more likely to match a generic format used by a library, or code that shouldn't know about specific Blender `Mesh` types. Various Notes: - The `.edge_verts` name is used to reflect a mapping between domains, similar to `.corner_verts`, etc. The period means that it the data shouldn't change arbitrarily by the user or procedural operations. - `edge[0]` is now used instead of `edge.v1` - Signed integers are used instead of unsigned to reduce the mixing of signed-ness, which can be error prone. - All of the previously used core mesh data types (`MVert`, `MEdge`, `MLoop`, `MPoly` are now deprecated. Only generic types are used). - The `vec2i` DNA type is used in the few C files where necessary. Pull Request: https://projects.blender.org/blender/blender/pulls/106638
2023-04-17 13:47:41 +02:00
const Span<int2> edges = mesh->edges();
/* By calling join() on the vertices of all edges, the AtomicDisjointSet contains information on
* which parts of the mesh are connected. */
threading::parallel_for(edges.index_range(), 1024, [&](const IndexRange range) {
Mesh: Move edges to a generic attribute Implements #95966, as the final step of #95965. This commit changes the storage of mesh edge vertex indices from the `MEdge` type to the generic `int2` attribute type. This follows the general design for geometry and the attribute system, where the data storage type and the usage semantics are separated. The main benefit of the change is reduced memory usage-- the requirements of storing mesh edges is reduced by 1/3. For example, this saves 8MB on a 1 million vertex grid. This also gives performance benefits to any memory-bound mesh processing algorithm that uses edges. Another benefit is that all of the edge's vertex indices are contiguous. In a few cases, it's helpful to process all of them as `Span<int>` rather than `Span<int2>`. Similarly, the type is more likely to match a generic format used by a library, or code that shouldn't know about specific Blender `Mesh` types. Various Notes: - The `.edge_verts` name is used to reflect a mapping between domains, similar to `.corner_verts`, etc. The period means that it the data shouldn't change arbitrarily by the user or procedural operations. - `edge[0]` is now used instead of `edge.v1` - Signed integers are used instead of unsigned to reduce the mixing of signed-ness, which can be error prone. - All of the previously used core mesh data types (`MVert`, `MEdge`, `MLoop`, `MPoly` are now deprecated. Only generic types are used). - The `vec2i` DNA type is used in the few C files where necessary. Pull Request: https://projects.blender.org/blender/blender/pulls/106638
2023-04-17 13:47:41 +02:00
for (const int2 &edge : edges.slice(range)) {
islands.join(edge[0], edge[1]);
}
});
bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
bke::SpanAttributeWriter<bool> select_vert = attributes.lookup_or_add_for_write_span<bool>(
".select_vert", bke::AttrDomain::Point);
Set<int> selected_roots;
for (const int i : vertex_indices) {
const int root = islands.find_root(i);
selected_roots.add(root);
}
threading::parallel_for(select_vert.span.index_range(), 1024, [&](const IndexRange range) {
for (const int i : range) {
const int root = islands.find_root(i);
if (selected_roots.contains(root)) {
select_vert.span[i] = select;
}
}
});
select_vert.finish();
paintvert_flush_flags(ob);
paintvert_tag_select_update(C, ob);
}
void paintvert_select_linked_pick(bContext *C,
Object *ob,
const int region_coordinates[2],
const bool select)
{
uint index = uint(-1);
if (!ED_mesh_pick_vert(C, ob, region_coordinates, ED_MESH_PICK_DEFAULT_VERT_DIST, true, &index))
{
return;
}
paintvert_select_linked_vertices(C, ob, {int(index)}, select);
}
void paintvert_select_linked(bContext *C, Object *ob)
{
using namespace blender;
Mesh *mesh = BKE_mesh_from_object(ob);
if (mesh == nullptr || mesh->faces_num == 0) {
return;
}
blender::bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
blender::bke::SpanAttributeWriter<bool> select_vert =
attributes.lookup_or_add_for_write_span<bool>(".select_vert", bke::AttrDomain::Point);
blender::Vector<int> indices;
for (const int i : select_vert.span.index_range()) {
if (!select_vert.span[i]) {
continue;
}
indices.append(i);
}
select_vert.finish();
paintvert_select_linked_vertices(C, ob, indices, true);
}
void paintvert_select_more(Mesh *mesh, const bool face_step)
{
using namespace blender;
bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
bke::SpanAttributeWriter<bool> select_vert = attributes.lookup_or_add_for_write_span<bool>(
".select_vert", bke::AttrDomain::Point);
const VArray<bool> hide_edge = *attributes.lookup_or_default<bool>(
".hide_edge", bke::AttrDomain::Edge, false);
const VArray<bool> hide_poly = *attributes.lookup_or_default<bool>(
".hide_poly", bke::AttrDomain::Face, false);
const OffsetIndices faces = mesh->faces();
const Span<int> corner_edges = mesh->corner_edges();
const Span<int> corner_verts = mesh->corner_verts();
Mesh: Move edges to a generic attribute Implements #95966, as the final step of #95965. This commit changes the storage of mesh edge vertex indices from the `MEdge` type to the generic `int2` attribute type. This follows the general design for geometry and the attribute system, where the data storage type and the usage semantics are separated. The main benefit of the change is reduced memory usage-- the requirements of storing mesh edges is reduced by 1/3. For example, this saves 8MB on a 1 million vertex grid. This also gives performance benefits to any memory-bound mesh processing algorithm that uses edges. Another benefit is that all of the edge's vertex indices are contiguous. In a few cases, it's helpful to process all of them as `Span<int>` rather than `Span<int2>`. Similarly, the type is more likely to match a generic format used by a library, or code that shouldn't know about specific Blender `Mesh` types. Various Notes: - The `.edge_verts` name is used to reflect a mapping between domains, similar to `.corner_verts`, etc. The period means that it the data shouldn't change arbitrarily by the user or procedural operations. - `edge[0]` is now used instead of `edge.v1` - Signed integers are used instead of unsigned to reduce the mixing of signed-ness, which can be error prone. - All of the previously used core mesh data types (`MVert`, `MEdge`, `MLoop`, `MPoly` are now deprecated. Only generic types are used). - The `vec2i` DNA type is used in the few C files where necessary. Pull Request: https://projects.blender.org/blender/blender/pulls/106638
2023-04-17 13:47:41 +02:00
const Span<int2> edges = mesh->edges();
Array<int> edge_to_face_offsets;
Array<int> edge_to_face_indices;
GroupedSpan<int> edge_to_face_map;
if (face_step) {
edge_to_face_map = bke::mesh::build_edge_to_face_map(
faces, corner_edges, mesh->edges_num, edge_to_face_offsets, edge_to_face_indices);
}
/* Need a copy of the selected verts that we can read from and is not modified. */
BitVector<> select_vert_original(mesh->verts_num, false);
for (int i = 0; i < mesh->verts_num; i++) {
select_vert_original[i].set(select_vert.span[i]);
}
/* If we iterated over faces we wouldn't extend the selection through edges that have no face
* attached to them. */
for (const int i : edges.index_range()) {
Mesh: Move edges to a generic attribute Implements #95966, as the final step of #95965. This commit changes the storage of mesh edge vertex indices from the `MEdge` type to the generic `int2` attribute type. This follows the general design for geometry and the attribute system, where the data storage type and the usage semantics are separated. The main benefit of the change is reduced memory usage-- the requirements of storing mesh edges is reduced by 1/3. For example, this saves 8MB on a 1 million vertex grid. This also gives performance benefits to any memory-bound mesh processing algorithm that uses edges. Another benefit is that all of the edge's vertex indices are contiguous. In a few cases, it's helpful to process all of them as `Span<int>` rather than `Span<int2>`. Similarly, the type is more likely to match a generic format used by a library, or code that shouldn't know about specific Blender `Mesh` types. Various Notes: - The `.edge_verts` name is used to reflect a mapping between domains, similar to `.corner_verts`, etc. The period means that it the data shouldn't change arbitrarily by the user or procedural operations. - `edge[0]` is now used instead of `edge.v1` - Signed integers are used instead of unsigned to reduce the mixing of signed-ness, which can be error prone. - All of the previously used core mesh data types (`MVert`, `MEdge`, `MLoop`, `MPoly` are now deprecated. Only generic types are used). - The `vec2i` DNA type is used in the few C files where necessary. Pull Request: https://projects.blender.org/blender/blender/pulls/106638
2023-04-17 13:47:41 +02:00
const int2 &edge = edges[i];
if ((!select_vert_original[edge[0]] && !select_vert_original[edge[1]]) || hide_edge[i]) {
continue;
}
Mesh: Move edges to a generic attribute Implements #95966, as the final step of #95965. This commit changes the storage of mesh edge vertex indices from the `MEdge` type to the generic `int2` attribute type. This follows the general design for geometry and the attribute system, where the data storage type and the usage semantics are separated. The main benefit of the change is reduced memory usage-- the requirements of storing mesh edges is reduced by 1/3. For example, this saves 8MB on a 1 million vertex grid. This also gives performance benefits to any memory-bound mesh processing algorithm that uses edges. Another benefit is that all of the edge's vertex indices are contiguous. In a few cases, it's helpful to process all of them as `Span<int>` rather than `Span<int2>`. Similarly, the type is more likely to match a generic format used by a library, or code that shouldn't know about specific Blender `Mesh` types. Various Notes: - The `.edge_verts` name is used to reflect a mapping between domains, similar to `.corner_verts`, etc. The period means that it the data shouldn't change arbitrarily by the user or procedural operations. - `edge[0]` is now used instead of `edge.v1` - Signed integers are used instead of unsigned to reduce the mixing of signed-ness, which can be error prone. - All of the previously used core mesh data types (`MVert`, `MEdge`, `MLoop`, `MPoly` are now deprecated. Only generic types are used). - The `vec2i` DNA type is used in the few C files where necessary. Pull Request: https://projects.blender.org/blender/blender/pulls/106638
2023-04-17 13:47:41 +02:00
select_vert.span[edge[0]] = true;
select_vert.span[edge[1]] = true;
if (!face_step) {
continue;
}
const Span<int> neighbor_polys = edge_to_face_map[i];
for (const int face_i : neighbor_polys) {
if (hide_poly[face_i]) {
continue;
}
const IndexRange face = faces[face_i];
for (const int vert : corner_verts.slice(face)) {
select_vert.span[vert] = true;
}
}
}
select_vert.finish();
}
void paintvert_select_less(Mesh *mesh, const bool face_step)
{
using namespace blender;
bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
bke::SpanAttributeWriter<bool> select_vert = attributes.lookup_or_add_for_write_span<bool>(
".select_vert", bke::AttrDomain::Point);
const VArray<bool> hide_edge = *attributes.lookup_or_default<bool>(
".hide_edge", bke::AttrDomain::Edge, false);
const VArray<bool> hide_poly = *attributes.lookup_or_default<bool>(
".hide_poly", bke::AttrDomain::Face, false);
const OffsetIndices faces = mesh->faces();
const Span<int> corner_edges = mesh->corner_edges();
const Span<int> corner_verts = mesh->corner_verts();
Mesh: Move edges to a generic attribute Implements #95966, as the final step of #95965. This commit changes the storage of mesh edge vertex indices from the `MEdge` type to the generic `int2` attribute type. This follows the general design for geometry and the attribute system, where the data storage type and the usage semantics are separated. The main benefit of the change is reduced memory usage-- the requirements of storing mesh edges is reduced by 1/3. For example, this saves 8MB on a 1 million vertex grid. This also gives performance benefits to any memory-bound mesh processing algorithm that uses edges. Another benefit is that all of the edge's vertex indices are contiguous. In a few cases, it's helpful to process all of them as `Span<int>` rather than `Span<int2>`. Similarly, the type is more likely to match a generic format used by a library, or code that shouldn't know about specific Blender `Mesh` types. Various Notes: - The `.edge_verts` name is used to reflect a mapping between domains, similar to `.corner_verts`, etc. The period means that it the data shouldn't change arbitrarily by the user or procedural operations. - `edge[0]` is now used instead of `edge.v1` - Signed integers are used instead of unsigned to reduce the mixing of signed-ness, which can be error prone. - All of the previously used core mesh data types (`MVert`, `MEdge`, `MLoop`, `MPoly` are now deprecated. Only generic types are used). - The `vec2i` DNA type is used in the few C files where necessary. Pull Request: https://projects.blender.org/blender/blender/pulls/106638
2023-04-17 13:47:41 +02:00
const Span<int2> edges = mesh->edges();
GroupedSpan<int> edge_to_face_map;
Array<int> edge_to_face_offsets;
Array<int> edge_to_face_indices;
if (face_step) {
edge_to_face_map = bke::mesh::build_edge_to_face_map(
faces, corner_edges, edges.size(), edge_to_face_offsets, edge_to_face_indices);
}
/* Need a copy of the selected verts that we can read from and is not modified. */
BitVector<> select_vert_original(mesh->verts_num);
for (int i = 0; i < mesh->verts_num; i++) {
select_vert_original[i].set(select_vert.span[i]);
}
for (const int i : edges.index_range()) {
Mesh: Move edges to a generic attribute Implements #95966, as the final step of #95965. This commit changes the storage of mesh edge vertex indices from the `MEdge` type to the generic `int2` attribute type. This follows the general design for geometry and the attribute system, where the data storage type and the usage semantics are separated. The main benefit of the change is reduced memory usage-- the requirements of storing mesh edges is reduced by 1/3. For example, this saves 8MB on a 1 million vertex grid. This also gives performance benefits to any memory-bound mesh processing algorithm that uses edges. Another benefit is that all of the edge's vertex indices are contiguous. In a few cases, it's helpful to process all of them as `Span<int>` rather than `Span<int2>`. Similarly, the type is more likely to match a generic format used by a library, or code that shouldn't know about specific Blender `Mesh` types. Various Notes: - The `.edge_verts` name is used to reflect a mapping between domains, similar to `.corner_verts`, etc. The period means that it the data shouldn't change arbitrarily by the user or procedural operations. - `edge[0]` is now used instead of `edge.v1` - Signed integers are used instead of unsigned to reduce the mixing of signed-ness, which can be error prone. - All of the previously used core mesh data types (`MVert`, `MEdge`, `MLoop`, `MPoly` are now deprecated. Only generic types are used). - The `vec2i` DNA type is used in the few C files where necessary. Pull Request: https://projects.blender.org/blender/blender/pulls/106638
2023-04-17 13:47:41 +02:00
const int2 &edge = edges[i];
if ((select_vert_original[edge[0]] && select_vert_original[edge[1]]) && !hide_edge[i]) {
continue;
}
Mesh: Move edges to a generic attribute Implements #95966, as the final step of #95965. This commit changes the storage of mesh edge vertex indices from the `MEdge` type to the generic `int2` attribute type. This follows the general design for geometry and the attribute system, where the data storage type and the usage semantics are separated. The main benefit of the change is reduced memory usage-- the requirements of storing mesh edges is reduced by 1/3. For example, this saves 8MB on a 1 million vertex grid. This also gives performance benefits to any memory-bound mesh processing algorithm that uses edges. Another benefit is that all of the edge's vertex indices are contiguous. In a few cases, it's helpful to process all of them as `Span<int>` rather than `Span<int2>`. Similarly, the type is more likely to match a generic format used by a library, or code that shouldn't know about specific Blender `Mesh` types. Various Notes: - The `.edge_verts` name is used to reflect a mapping between domains, similar to `.corner_verts`, etc. The period means that it the data shouldn't change arbitrarily by the user or procedural operations. - `edge[0]` is now used instead of `edge.v1` - Signed integers are used instead of unsigned to reduce the mixing of signed-ness, which can be error prone. - All of the previously used core mesh data types (`MVert`, `MEdge`, `MLoop`, `MPoly` are now deprecated. Only generic types are used). - The `vec2i` DNA type is used in the few C files where necessary. Pull Request: https://projects.blender.org/blender/blender/pulls/106638
2023-04-17 13:47:41 +02:00
select_vert.span[edge[0]] = false;
select_vert.span[edge[1]] = false;
if (!face_step) {
continue;
}
for (const int face_i : edge_to_face_map[i]) {
if (hide_poly[face_i]) {
continue;
}
const IndexRange face = faces[face_i];
for (const int vert : corner_verts.slice(face)) {
select_vert.span[vert] = false;
}
}
}
select_vert.finish();
}
void paintvert_tag_select_update(bContext *C, Object *ob)
{
DEG_id_tag_update(static_cast<ID *>(ob->data), ID_RECALC_SYNC_TO_EVAL | ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
}
bool paintvert_deselect_all_visible(Object *ob, int action, bool flush_flags)
{
using namespace blender;
Mesh *mesh = BKE_mesh_from_object(ob);
if (mesh == nullptr) {
return false;
}
bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
const VArray<bool> hide_vert = *attributes.lookup_or_default<bool>(
".hide_vert", bke::AttrDomain::Point, false);
2022-09-23 09:38:37 -05:00
bke::SpanAttributeWriter<bool> select_vert = attributes.lookup_or_add_for_write_span<bool>(
".select_vert", bke::AttrDomain::Point);
2013-08-03 16:55:49 +00:00
if (action == SEL_TOGGLE) {
action = SEL_SELECT;
for (int i = 0; i < mesh->verts_num; i++) {
2022-09-23 09:38:37 -05:00
if (!hide_vert[i] && select_vert.span[i]) {
2013-08-03 16:55:49 +00:00
action = SEL_DESELECT;
break;
}
}
}
bool changed = false;
for (int i = 0; i < mesh->verts_num; i++) {
2022-09-23 09:38:37 -05:00
if (hide_vert[i]) {
continue;
}
const bool old_selection = select_vert.span[i];
switch (action) {
case SEL_SELECT:
select_vert.span[i] = true;
break;
case SEL_DESELECT:
select_vert.span[i] = false;
break;
case SEL_INVERT:
select_vert.span[i] = !select_vert.span[i];
break;
}
if (old_selection != select_vert.span[i]) {
changed = true;
}
}
2022-09-23 09:38:37 -05:00
select_vert.finish();
if (changed) {
/* handle mselect */
if (action == SEL_SELECT) {
/* pass */
}
else if (ELEM(action, SEL_DESELECT, SEL_INVERT)) {
BKE_mesh_mselect_clear(mesh);
}
else {
BKE_mesh_mselect_validate(mesh);
}
if (flush_flags) {
paintvert_flush_flags(ob);
}
}
return changed;
}
void paintvert_select_ungrouped(Object *ob, bool extend, bool flush_flags)
{
using namespace blender;
Mesh *mesh = BKE_mesh_from_object(ob);
if (mesh == nullptr) {
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
2022-09-05 11:56:34 -05:00
return;
}
const Span<MDeformVert> dverts = mesh->deform_verts();
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
2022-09-05 11:56:34 -05:00
if (dverts.is_empty()) {
return;
}
if (!extend) {
paintvert_deselect_all_visible(ob, SEL_DESELECT, false);
}
bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
const VArray<bool> hide_vert = *attributes.lookup_or_default<bool>(
".hide_vert", bke::AttrDomain::Point, false);
2022-09-23 09:38:37 -05:00
bke::SpanAttributeWriter<bool> select_vert = attributes.lookup_or_add_for_write_span<bool>(
".select_vert", bke::AttrDomain::Point);
2022-09-23 09:38:37 -05:00
for (const int i : select_vert.span.index_range()) {
if (!hide_vert[i]) {
2022-09-23 09:38:37 -05:00
if (dverts[i].dw == nullptr) {
/* if null weight then not grouped */
2022-09-23 09:38:37 -05:00
select_vert.span[i] = true;
}
}
}
2022-09-23 09:38:37 -05:00
select_vert.finish();
if (flush_flags) {
paintvert_flush_flags(ob);
}
}
void paintvert_hide(bContext *C, Object *ob, const bool unselected)
{
using namespace blender;
Mesh *mesh = BKE_mesh_from_object(ob);
if (mesh == nullptr || mesh->verts_num == 0) {
return;
}
bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
bke::SpanAttributeWriter<bool> hide_vert = attributes.lookup_or_add_for_write_span<bool>(
".hide_vert", bke::AttrDomain::Point);
2022-09-23 09:38:37 -05:00
bke::SpanAttributeWriter<bool> select_vert = attributes.lookup_or_add_for_write_span<bool>(
".select_vert", bke::AttrDomain::Point);
2022-09-23 09:38:37 -05:00
for (const int i : hide_vert.span.index_range()) {
if (!hide_vert.span[i]) {
2022-09-23 09:38:37 -05:00
if (!select_vert.span[i] == unselected) {
hide_vert.span[i] = true;
}
}
if (hide_vert.span[i]) {
2022-09-23 09:38:37 -05:00
select_vert.span[i] = false;
}
}
hide_vert.finish();
2022-09-23 09:38:37 -05:00
select_vert.finish();
bke::mesh_hide_vert_flush(*mesh);
paintvert_flush_flags(ob);
paintvert_tag_select_update(C, ob);
}
void paintvert_reveal(bContext *C, Object *ob, const bool select)
{
using namespace blender;
Mesh *mesh = BKE_mesh_from_object(ob);
if (mesh == nullptr || mesh->verts_num == 0) {
return;
}
bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
const VArray<bool> hide_vert = *attributes.lookup_or_default<bool>(
".hide_vert", bke::AttrDomain::Point, false);
2022-09-23 09:38:37 -05:00
bke::SpanAttributeWriter<bool> select_vert = attributes.lookup_or_add_for_write_span<bool>(
".select_vert", bke::AttrDomain::Point);
2022-09-23 09:38:37 -05:00
for (const int i : select_vert.span.index_range()) {
if (hide_vert[i]) {
2022-09-23 09:38:37 -05:00
select_vert.span[i] = select;
}
}
2022-09-23 09:38:37 -05:00
select_vert.finish();
/* Remove the hide attribute to reveal all vertices. */
attributes.remove(".hide_vert");
bke::mesh_hide_vert_flush(*mesh);
paintvert_flush_flags(ob);
paintvert_tag_select_update(C, ob);
}