Cleanup: move flip faces code from nodes to geometry module
This commit is contained in:
@@ -18,6 +18,7 @@ set(SRC
|
||||
intern/add_curves_on_mesh.cc
|
||||
intern/curve_constraints.cc
|
||||
intern/fillet_curves.cc
|
||||
intern/mesh_flip_faces.cc
|
||||
intern/mesh_merge_by_distance.cc
|
||||
intern/mesh_primitive_cuboid.cc
|
||||
intern/mesh_split_edges.cc
|
||||
@@ -37,6 +38,7 @@ set(SRC
|
||||
GEO_add_curves_on_mesh.hh
|
||||
GEO_curve_constraints.hh
|
||||
GEO_fillet_curves.hh
|
||||
GEO_mesh_flip_faces.hh
|
||||
GEO_mesh_merge_by_distance.hh
|
||||
GEO_mesh_primitive_cuboid.hh
|
||||
GEO_mesh_split_edges.hh
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BLI_index_mask.hh"
|
||||
|
||||
struct Mesh;
|
||||
|
||||
namespace blender::geometry {
|
||||
|
||||
/**
|
||||
* Reverse the order of the vertices in the selected faces. This effectively changes the
|
||||
* direction of the face normal.
|
||||
*/
|
||||
void flip_faces(Mesh &mesh, const IndexMask &selection);
|
||||
|
||||
} // namespace blender::geometry
|
||||
@@ -0,0 +1,67 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "GEO_mesh_flip_faces.hh"
|
||||
|
||||
#include "DNA_mesh_types.h"
|
||||
|
||||
#include "BLI_task.hh"
|
||||
|
||||
#include "BKE_attribute.hh"
|
||||
#include "BKE_attribute_math.hh"
|
||||
#include "BKE_mesh.hh"
|
||||
|
||||
namespace blender::geometry {
|
||||
|
||||
void flip_faces(Mesh &mesh, const IndexMask &selection)
|
||||
{
|
||||
if (mesh.totpoly == 0 || selection.is_empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const Span<MPoly> polys = mesh.polys();
|
||||
MutableSpan<int> corner_verts = mesh.corner_verts_for_write();
|
||||
MutableSpan<int> corner_edges = mesh.corner_edges_for_write();
|
||||
|
||||
threading::parallel_for(selection.index_range(), 1024, [&](const IndexRange range) {
|
||||
for (const int i : selection.slice(range)) {
|
||||
const IndexRange poly(polys[i].loopstart, polys[i].totloop);
|
||||
for (const int j : IndexRange(poly.size() / 2)) {
|
||||
const int a = poly[j + 1];
|
||||
const int b = poly.last(j);
|
||||
std::swap(corner_verts[a], corner_verts[b]);
|
||||
std::swap(corner_edges[a - 1], corner_edges[b]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
|
||||
attributes.for_all(
|
||||
[&](const bke::AttributeIDRef &attribute_id, const bke::AttributeMetaData &meta_data) {
|
||||
if (meta_data.data_type == CD_PROP_STRING) {
|
||||
return true;
|
||||
}
|
||||
if (meta_data.domain != ATTR_DOMAIN_CORNER) {
|
||||
return true;
|
||||
}
|
||||
if (ELEM(attribute_id.name(), ".corner_vert", ".corner_edge")) {
|
||||
return true;
|
||||
}
|
||||
bke::GSpanAttributeWriter attribute = attributes.lookup_for_write_span(attribute_id);
|
||||
attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
MutableSpan<T> dst_span = attribute.span.typed<T>();
|
||||
threading::parallel_for(selection.index_range(), 1024, [&](const IndexRange range) {
|
||||
for (const int i : selection.slice(range)) {
|
||||
const IndexRange poly(polys[i].loopstart, polys[i].totloop);
|
||||
dst_span.slice(poly.drop_front(1)).reverse();
|
||||
}
|
||||
});
|
||||
});
|
||||
attribute.finish();
|
||||
return true;
|
||||
});
|
||||
|
||||
BKE_mesh_tag_topology_changed(&mesh);
|
||||
}
|
||||
|
||||
} // namespace blender::geometry
|
||||
@@ -7,6 +7,8 @@
|
||||
|
||||
#include "BKE_attribute_math.hh"
|
||||
|
||||
#include "GEO_mesh_flip_faces.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
namespace blender::nodes::node_geo_flip_faces_cc {
|
||||
@@ -29,48 +31,7 @@ static void mesh_flip_faces(Mesh &mesh, const Field<bool> &selection_field)
|
||||
evaluator.evaluate();
|
||||
const IndexMask selection = evaluator.get_evaluated_as_mask(0);
|
||||
|
||||
const Span<MPoly> polys = mesh.polys();
|
||||
MutableSpan<int> corner_verts = mesh.corner_verts_for_write();
|
||||
MutableSpan<int> corner_edges = mesh.corner_edges_for_write();
|
||||
|
||||
threading::parallel_for(selection.index_range(), 1024, [&](const IndexRange range) {
|
||||
for (const int i : selection.slice(range)) {
|
||||
const IndexRange poly(polys[i].loopstart, polys[i].totloop);
|
||||
for (const int j : IndexRange(poly.size() / 2)) {
|
||||
const int a = poly[j + 1];
|
||||
const int b = poly.last(j);
|
||||
std::swap(corner_verts[a], corner_verts[b]);
|
||||
std::swap(corner_edges[a - 1], corner_edges[b]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
MutableAttributeAccessor attributes = mesh.attributes_for_write();
|
||||
attributes.for_all(
|
||||
[&](const bke::AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
|
||||
if (meta_data.data_type == CD_PROP_STRING) {
|
||||
return true;
|
||||
}
|
||||
if (meta_data.domain != ATTR_DOMAIN_CORNER) {
|
||||
return true;
|
||||
}
|
||||
if (ELEM(attribute_id.name(), ".corner_vert", ".corner_edge")) {
|
||||
return true;
|
||||
}
|
||||
GSpanAttributeWriter attribute = attributes.lookup_for_write_span(attribute_id);
|
||||
attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
MutableSpan<T> dst_span = attribute.span.typed<T>();
|
||||
threading::parallel_for(selection.index_range(), 1024, [&](const IndexRange range) {
|
||||
for (const int i : selection.slice(range)) {
|
||||
const IndexRange poly(polys[i].loopstart, polys[i].totloop);
|
||||
dst_span.slice(poly.drop_front(1)).reverse();
|
||||
}
|
||||
});
|
||||
});
|
||||
attribute.finish();
|
||||
return true;
|
||||
});
|
||||
geometry::flip_faces(mesh, selection);
|
||||
}
|
||||
|
||||
static void node_geo_exec(GeoNodeExecParams params)
|
||||
|
||||
Reference in New Issue
Block a user