diff options
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/blenkernel/BKE_node.h | 1 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/node.cc | 1 | ||||
-rw-r--r-- | source/blender/nodes/NOD_geometry.h | 1 | ||||
-rw-r--r-- | source/blender/nodes/NOD_static_types.h | 1 | ||||
-rw-r--r-- | source/blender/nodes/geometry/CMakeLists.txt | 1 | ||||
-rw-r--r-- | source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc | 114 |
6 files changed, 119 insertions, 0 deletions
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 1ee8c91ff3e..ccea76fc24d 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -1630,6 +1630,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree, #define GEO_NODE_INPUT_MESH_EDGE_ANGLE 1147 #define GEO_NODE_FIELD_AT_INDEX 1148 #define GEO_NODE_CURVE_PRIMITIVE_ARC 1149 +#define GEO_NODE_FLIP_FACES 1150 /** \} */ diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index 4bac8c150df..9ee54c9ebeb 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -4769,6 +4769,7 @@ static void registerGeometryNodes() register_node_type_geo_dual_mesh(); register_node_type_geo_edge_split(); register_node_type_geo_field_at_index(); + register_node_type_geo_flip_faces(); register_node_type_geo_geometry_to_instance(); register_node_type_geo_image_texture(); register_node_type_geo_input_curve_handles(); diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h index 1548ba32abc..ff4036308c6 100644 --- a/source/blender/nodes/NOD_geometry.h +++ b/source/blender/nodes/NOD_geometry.h @@ -100,6 +100,7 @@ void register_node_type_geo_distribute_points_on_faces(void); void register_node_type_geo_dual_mesh(void); void register_node_type_geo_edge_split(void); void register_node_type_geo_field_at_index(void); +void register_node_type_geo_flip_faces(void); void register_node_type_geo_geometry_to_instance(void); void register_node_type_geo_image_texture(void); void register_node_type_geo_input_curve_handles(void); diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index 1657a924ddb..53d6d64ef84 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -355,6 +355,7 @@ DefNode(GeometryNode, GEO_NODE_DUAL_MESH, 0, "DUAL_MESH", DualMesh, "Dual Mesh", DefNode(GeometryNode, GEO_NODE_FIELD_AT_INDEX, def_geo_field_at_index, "FIELD_AT_INDEX", FieldAtIndex, "Field at Index", "") DefNode(GeometryNode, GEO_NODE_FILL_CURVE, def_geo_curve_fill, "FILL_CURVE", FillCurve, "Fill Curve", "") DefNode(GeometryNode, GEO_NODE_FILLET_CURVE, def_geo_curve_fillet, "FILLET_CURVE", FilletCurve, "Fillet Curve", "") +DefNode(GeometryNode, GEO_NODE_FLIP_FACES, 0, "FLIP_FACES", FlipFaces, "Flip Faces", "") DefNode(GeometryNode, GEO_NODE_GEOMETRY_TO_INSTANCE, 0, "GEOMETRY_TO_INSTANCE", GeometryToInstance, "Geometry to Instance", "") DefNode(GeometryNode, GEO_NODE_IMAGE_TEXTURE, def_geo_image_texture, "IMAGE_TEXTURE", ImageTexture, "Image Texture", "") DefNode(GeometryNode, GEO_NODE_INPUT_CURVE_HANDLES, 0, "INPUT_CURVE_HANDLES", InputCurveHandlePositions, "Curve Handle Positions", "") diff --git a/source/blender/nodes/geometry/CMakeLists.txt b/source/blender/nodes/geometry/CMakeLists.txt index 7ce8988a075..37d7843020a 100644 --- a/source/blender/nodes/geometry/CMakeLists.txt +++ b/source/blender/nodes/geometry/CMakeLists.txt @@ -118,6 +118,7 @@ set(SRC nodes/node_geo_dual_mesh.cc nodes/node_geo_edge_split.cc nodes/node_geo_field_at_index.cc + nodes/node_geo_flip_faces.cc nodes/node_geo_geometry_to_instance.cc nodes/node_geo_image_texture.cc nodes/node_geo_input_curve_handles.cc diff --git a/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc b/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc new file mode 100644 index 00000000000..41970d75dfe --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc @@ -0,0 +1,114 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "BKE_mesh.h" +#include "BKE_mesh_runtime.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "BKE_attribute_math.hh" + +#include "node_geometry_util.hh" + +namespace blender::nodes::node_geo_flip_faces_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH); + b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); + b.add_output<decl::Geometry>(N_("Mesh")); +} + +static void mesh_flip_faces(MeshComponent &component, const Field<bool> &selection_field) +{ + GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_FACE}; + const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_FACE); + if (domain_size == 0) { + return; + } + fn::FieldEvaluator evaluator{field_context, domain_size}; + evaluator.add(selection_field); + evaluator.evaluate(); + const IndexMask selection = evaluator.get_evaluated_as_mask(0); + + Mesh *mesh = component.get_for_write(); + + mesh->mloop = (MLoop *)CustomData_duplicate_referenced_layer( + &mesh->ldata, CD_MLOOP, mesh->totloop); + Span<MPoly> polys{mesh->mpoly, mesh->totpoly}; + MutableSpan<MLoop> loops{mesh->mloop, mesh->totloop}; + + for (const int i : selection.index_range()) { + const MPoly &poly = polys[selection[i]]; + int start = poly.loopstart; + for (const int j : IndexRange(poly.totloop / 2)) { + const int index1 = start + j + 1; + const int index2 = start + poly.totloop - j - 1; + std::swap(loops[index1].v, loops[index2].v); + std::swap(loops[index1 - 1].e, loops[index2].e); + } + } + + component.attribute_foreach( + [&](const bke::AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) { + if (meta_data.domain == ATTR_DOMAIN_CORNER) { + OutputAttribute attribute = component.attribute_try_get_for_output( + attribute_id, ATTR_DOMAIN_CORNER, meta_data.data_type, nullptr); + attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) { + using T = decltype(dummy); + MutableSpan<T> dst_span = attribute.as_span<T>(); + for (const int j : selection.index_range()) { + const MPoly &poly = polys[selection[j]]; + dst_span.slice(poly.loopstart + 1, poly.totloop - 1).reverse(); + } + }); + attribute.save(); + } + return true; + }); +} + +static void node_geo_exec(GeoNodeExecParams params) +{ + GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh"); + + const Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); + + geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + if (!geometry_set.has_mesh()) { + return; + } + MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>(); + mesh_flip_faces(mesh_component, selection_field); + }); + + params.set_output("Mesh", std::move(geometry_set)); +} + +} // namespace blender::nodes::node_geo_flip_faces_cc + +void register_node_type_geo_flip_faces() +{ + namespace file_ns = blender::nodes::node_geo_flip_faces_cc; + + static bNodeType ntype; + + geo_node_type_base(&ntype, GEO_NODE_FLIP_FACES, "Flip Faces", NODE_CLASS_GEOMETRY); + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; + nodeRegisterType(&ntype); +} |