From a28e5189178359d09b1869528f0a97030ab309bd Mon Sep 17 00:00:00 2001 From: Fabian Schempp Date: Fri, 13 Aug 2021 23:57:13 +0200 Subject: Changes based on review by Hans Goudey (HooglyBoogly) --- release/scripts/startup/nodeitems_builtins.py | 2 +- source/blender/blenkernel/BKE_node.h | 2 +- source/blender/blenkernel/intern/node.cc | 2 +- source/blender/bmesh/intern/bmesh_mesh.c | 62 +++--- source/blender/bmesh/intern/bmesh_mesh.h | 7 +- source/blender/makesrna/intern/rna_nodetree.c | 2 +- source/blender/nodes/CMakeLists.txt | 2 +- source/blender/nodes/NOD_geometry.h | 2 +- source/blender/nodes/NOD_static_types.h | 2 +- .../nodes/geometry/nodes/node_geo_extrude.cc | 227 --------------------- .../nodes/geometry/nodes/node_geo_mesh_inset.cc | 215 +++++++++++++++++++ 11 files changed, 256 insertions(+), 269 deletions(-) delete mode 100644 source/blender/nodes/geometry/nodes/node_geo_extrude.cc create mode 100644 source/blender/nodes/geometry/nodes/node_geo_mesh_inset.cc diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py index c66d8d3feac..1bc1a2555a5 100644 --- a/release/scripts/startup/nodeitems_builtins.py +++ b/release/scripts/startup/nodeitems_builtins.py @@ -552,7 +552,7 @@ geometry_node_categories = [ NodeItem("GeometryNodeEdgeSplit"), NodeItem("GeometryNodeSubdivisionSurface"), NodeItem("GeometryNodeMeshSubdivide"), - NodeItem("GeometryNodeExtrude"), + NodeItem("GeometryNodeMeshInset"), ]), GeometryNodeCategory("GEO_PRIMITIVES_MESH", "Mesh Primitives", items=[ NodeItem("GeometryNodeMeshCircle"), diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index bfa3c58cbe2..c9f5777109a 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -1476,7 +1476,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree, #define GEO_NODE_CURVE_TRIM 1071 #define GEO_NODE_CURVE_SET_HANDLES 1072 #define GEO_NODE_CURVE_SPLINE_TYPE 1073 -#define GEO_NODE_EXTRUDE 1074 +#define GEO_NODE_MESH_INSET 1074 /** \} */ diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index d30d0509867..1c990c409f6 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -5156,7 +5156,7 @@ static void registerGeometryNodes() register_node_type_geo_curve_trim(); register_node_type_geo_delete_geometry(); register_node_type_geo_edge_split(); - register_node_type_geo_extrude(); + register_node_type_geo_mesh_inset(); register_node_type_geo_input_material(); register_node_type_geo_is_viewport(); register_node_type_geo_join_geometry(); diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c index 217c3502b40..bf123ee23f2 100644 --- a/source/blender/bmesh/intern/bmesh_mesh.c +++ b/source/blender/bmesh/intern/bmesh_mesh.c @@ -1453,10 +1453,9 @@ void BM_select_vertices(BMesh *bm, const bool *mask) { BMIter iter; BMVert *v; - int i = 0; - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + int i; + BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) { BM_elem_flag_set(v, BM_ELEM_SELECT, mask[i]); - i++; } } @@ -1467,10 +1466,9 @@ void BM_select_edges(BMesh *bm, const bool *mask) { BMIter iter; BMEdge *e; - int i = 0; - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + int i; + BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) { BM_elem_flag_set(e, BM_ELEM_SELECT, mask[i]); - i++; } } @@ -1482,34 +1480,28 @@ void BM_select_faces(BMesh *bm, const bool *mask) BMIter iter; BMFace *f; int i = 0; - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, i) { BM_elem_flag_set(f, BM_ELEM_SELECT, mask[i]); - i++; } } -void BM_get_selected_faces(BMesh *bm, bool **selection) +void BM_get_selected_faces(BMesh *bm, bool *selection) { BMIter iter; BMFace *f; int i = 0; - *selection = MEM_malloc_arrayN((size_t)bm->totface, sizeof(bool), "bm faces"); - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - (*selection)[i] = BM_elem_flag_test(f, BM_ELEM_SELECT); - i++; + BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, i) { + selection[i] = BM_elem_flag_test(f, BM_ELEM_SELECT); } - // BMO_slot_map_elem_get() } -void BM_get_tagged_faces(BMesh *bm, bool **selection) +void BM_get_tagged_faces(BMesh *bm, bool *selection) { BMIter iter; BMFace *f; - int i = 0; - *selection = MEM_malloc_arrayN((size_t)bm->totface, sizeof(bool), "bm faces"); - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - (*selection)[i] = BM_elem_flag_test(f, BM_ELEM_TAG); - i++; + int i; + BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, i) { + selection[i] = BM_elem_flag_test(f, BM_ELEM_TAG); } } @@ -1517,23 +1509,19 @@ void BM_tag_new_faces(BMesh *bm, BMOperator *b_mesh_operator) { BMIter iter; BMFace *f; - int i = 0; - //*selection = MEM_malloc_arrayN((size_t)bm->totface, sizeof(bool), "bm faces"); BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false); BMO_ITER (f, &iter, b_mesh_operator->slots_out, "faces.out", BM_FACE) { BM_elem_flag_enable(f, BM_ELEM_TAG); } - // BMO_slot_map_elem_get() } void BM_tag_vertices(BMesh *bm, const bool *mask) { BMIter iter; BMVert *v; - int i = 0; - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + int i; + BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) { BM_elem_flag_set(v, BM_ELEM_TAG, mask[i]); - i++; } } @@ -1544,10 +1532,9 @@ void BM_tag_edges(BMesh *bm, const bool *mask) { BMIter iter; BMEdge *e; - int i = 0; - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + int i; + BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) { BM_elem_flag_set(e, BM_ELEM_TAG, mask[i]); - i++; } } @@ -1558,10 +1545,21 @@ void BM_tag_faces(BMesh *bm, const bool *mask) { BMIter iter; BMFace *f; - int i = 0; - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + int i; + BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, i) { BM_elem_flag_set(f, BM_ELEM_TAG, mask[i]); - i++; + } +} + +void BM_untag_faces_by_tag(BMesh *bm, int tag) +{ + BMIter iter; + BMFace *f; + int i; + BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, i) { + if (BM_elem_flag_test(f, tag)) { + BM_elem_flag_disable(f, BM_ELEM_TAG); + } } } /** \} */ diff --git a/source/blender/bmesh/intern/bmesh_mesh.h b/source/blender/bmesh/intern/bmesh_mesh.h index 99baaa1421f..f1cb8bf0880 100644 --- a/source/blender/bmesh/intern/bmesh_mesh.h +++ b/source/blender/bmesh/intern/bmesh_mesh.h @@ -138,9 +138,10 @@ void BM_mesh_vert_coords_apply_with_mat4(BMesh *bm, void BM_select_vertices(BMesh *bm, const bool *mask); void BM_select_edges(BMesh *bm, const bool *mask); void BM_select_faces(BMesh *bm, const bool *mask); -void BM_get_selected_faces(BMesh *bm, bool **selection); +void BM_get_selected_faces(BMesh *bm, bool *selection); void BM_tag_vertices(BMesh *bm, const bool *mask); void BM_tag_edges(BMesh *bm, const bool *mask); void BM_tag_faces(BMesh *bm, const bool *mask); -void BM_get_tagged_faces(BMesh *bm, bool **selection); -void BM_tag_new_faces(BMesh *bm, BMOperator *b_mesh_operator); \ No newline at end of file +void BM_untag_faces_by_tag(BMesh *bm, int tag); +void BM_get_tagged_faces(BMesh *bm, bool *selection); +void BM_tag_new_faces(BMesh *bm, BMOperator *b_mesh_operator); diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 01e0f84f87e..802690b4bb6 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -10160,7 +10160,7 @@ static void def_geo_attribute_transfer(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } -static void def_geo_extrude(StructRNA *srna) +static void def_geo_mesh_inset(StructRNA *srna) { PropertyRNA *prop; diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index 7668d0f4f04..10dcf942b91 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -183,7 +183,7 @@ set(SRC geometry/nodes/node_geo_curve_trim.cc geometry/nodes/node_geo_delete_geometry.cc geometry/nodes/node_geo_edge_split.cc - geometry/nodes/node_geo_extrude.cc + geometry/nodes/node_geo_mesh_inset.cc geometry/nodes/node_geo_input_material.cc geometry/nodes/node_geo_is_viewport.cc geometry/nodes/node_geo_join_geometry.cc diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h index 868c79ed2f6..26f81efca72 100644 --- a/source/blender/nodes/NOD_geometry.h +++ b/source/blender/nodes/NOD_geometry.h @@ -70,7 +70,7 @@ void register_node_type_geo_curve_to_points(void); void register_node_type_geo_curve_trim(void); void register_node_type_geo_delete_geometry(void); void register_node_type_geo_edge_split(void); -void register_node_type_geo_extrude(void); +void register_node_type_geo_mesh_inset(void); void register_node_type_geo_input_material(void); void register_node_type_geo_is_viewport(void); void register_node_type_geo_join_geometry(void); diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index 16ba3000fba..cc5be95208c 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -310,7 +310,7 @@ DefNode(GeometryNode, GEO_NODE_CURVE_TO_POINTS, def_geo_curve_to_points, "CURVE_ DefNode(GeometryNode, GEO_NODE_CURVE_TRIM, def_geo_curve_trim, "CURVE_TRIM", CurveTrim, "Curve Trim", "") DefNode(GeometryNode, GEO_NODE_DELETE_GEOMETRY, 0, "DELETE_GEOMETRY", DeleteGeometry, "Delete Geometry", "") DefNode(GeometryNode, GEO_NODE_EDGE_SPLIT, 0, "EDGE_SPLIT", EdgeSplit, "Edge Split", "") -DefNode(GeometryNode, GEO_NODE_EXTRUDE, def_geo_extrude, "EXTRUDE", Extrude, "Extrude", "") +DefNode(GeometryNode, GEO_NODE_MESH_INSET, def_geo_mesh_inset, "MESH_INSET", MeshInset, "Mesh Inset", "") DefNode(GeometryNode, GEO_NODE_INPUT_MATERIAL, def_geo_input_material, "INPUT_MATERIAL", InputMaterial, "Material", "") DefNode(GeometryNode, GEO_NODE_IS_VIEWPORT, 0, "IS_VIEWPORT", IsViewport, "Is Viewport", "") DefNode(GeometryNode, GEO_NODE_JOIN_GEOMETRY, 0, "JOIN_GEOMETRY", JoinGeometry, "Join Geometry", "") diff --git a/source/blender/nodes/geometry/nodes/node_geo_extrude.cc b/source/blender/nodes/geometry/nodes/node_geo_extrude.cc deleted file mode 100644 index 67645b060dc..00000000000 --- a/source/blender/nodes/geometry/nodes/node_geo_extrude.cc +++ /dev/null @@ -1,227 +0,0 @@ -/* - * 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 "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" - -#include "BKE_mesh.h" -#include "BKE_node.h" - -#include "UI_interface.h" -#include "UI_resources.h" - -#include "bmesh.h" -#include "bmesh_tools.h" - -#include "node_geometry_util.hh" - -static bNodeSocketTemplate geo_node_extrude_in[] = { - {SOCK_GEOMETRY, N_("Geometry")}, - {SOCK_STRING, N_("Distance")}, - {SOCK_FLOAT, N_("Distance"), 0.0f, 0, 0, 0, FLT_MIN, FLT_MAX, PROP_DISTANCE}, - {SOCK_STRING, N_("Inset")}, - {SOCK_FLOAT, N_("Inset"), 0.0f, 0, 0, 0, FLT_MIN, FLT_MAX, PROP_DISTANCE}, - {SOCK_BOOLEAN, N_("Individual")}, - {SOCK_STRING, N_("Selection")}, - {SOCK_STRING, N_("Top Face")}, - {SOCK_STRING, N_("Side Face")}, - {-1, ""}, -}; - -static bNodeSocketTemplate geo_node_extrude_out[] = { - {SOCK_GEOMETRY, N_("Geometry")}, - {-1, ""}, -}; - -static void geo_node_extrude_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiLayoutSetPropSep(layout, true); - uiLayoutSetPropDecorate(layout, false); - uiItemR(layout, ptr, "distance_mode", 0, nullptr, ICON_NONE); - uiItemR(layout, ptr, "inset_mode", 0, nullptr, ICON_NONE); -} - -static void geo_node_extrude_init(bNodeTree *UNUSED(tree), bNode *node) -{ - node->custom1 = GEO_NODE_ATTRIBUTE_INPUT_FLOAT; - node->custom2 = GEO_NODE_ATTRIBUTE_INPUT_FLOAT; -} - -static void geo_node_extrude_update(bNodeTree *UNUSED(ntree), bNode *node) -{ - blender::nodes::update_attribute_input_socket_availabilities( - *node, "Distance", (GeometryNodeAttributeInputMode)node->custom1, true); - blender::nodes::update_attribute_input_socket_availabilities( - *node, "Inset", (GeometryNodeAttributeInputMode)node->custom2, true); -} - -using blender::Span; - -static Mesh *extrude_mesh(const Mesh *mesh, - const Span selection, - const Span distance, - const Span inset, - const bool inset_individual_faces, - bool **selection_top_faces_out, - bool **selection_all_faces_out) -{ - const BMeshCreateParams bmesh_create_params = {true}; - const BMeshFromMeshParams bmesh_from_mesh_params = { - true, 0, 0, 0, {CD_MASK_ORIGINDEX, CD_MASK_ORIGINDEX, CD_MASK_ORIGINDEX}}; - - BMesh *bm = BKE_mesh_to_bmesh_ex(mesh, &bmesh_create_params, &bmesh_from_mesh_params); - - BM_select_faces(bm, selection.data()); - BMOperator op; - if (inset_individual_faces) { - BMO_op_initf(bm, - &op, - 0, - "inset_individual faces=%hf use_even_offset=%b thickness=%f depth=%f " - "thickness_array=%p depth_array=%p use_attributes=%b", - BM_ELEM_SELECT, - true, - inset[0], - distance[0], - inset.data(), - distance.data(), - true); - } - else { - BMO_op_initf(bm, - &op, - 0, - "inset_region faces=%hf use_boundary=%b use_even_offset=%b thickness=%f depth=%f " - "thickness_array=%p depth_array=%p use_attributes=%b", - BM_ELEM_SELECT, - true, - true, - inset[0], - distance[0], - inset.data(), - distance.data(), - true); - } - BM_tag_new_faces(bm, &op); - BMO_op_exec(bm, &op); - - CustomData_MeshMasks cd_mask_extra = {CD_MASK_ORIGINDEX, CD_MASK_ORIGINDEX, CD_MASK_ORIGINDEX}; - - Mesh *result = BKE_mesh_from_bmesh_for_eval_nomain(bm, &cd_mask_extra, mesh); - BM_get_selected_faces(bm, selection_top_faces_out); - BM_get_tagged_faces(bm, selection_all_faces_out); - - BM_mesh_free(bm); - - BKE_mesh_normals_tag_dirty(result); - - return result; -} - -namespace blender::nodes { -static void geo_node_extrude_exec(GeoNodeExecParams params) -{ - GeometrySet geometry_set = params.extract_input("Geometry"); - - geometry_set = geometry_set_realize_instances(geometry_set); - - MeshComponent &mesh_component = geometry_set.get_component_for_write(); - if (mesh_component.has_mesh()) { - const bool default_selection = true; - GVArray_Typed selection_attribute = params.get_input_attribute( - "Selection", mesh_component, ATTR_DOMAIN_FACE, default_selection); - VArray_Span selection{selection_attribute}; - const Mesh *input_mesh = mesh_component.get_for_read(); - // const float distance = params.extract_input("Distance"); - // const float inset = params.extract_input("Inset"); - - AttributeDomain attribute_domain = ATTR_DOMAIN_POINT; - const bool inset_individual_faces = params.extract_input("Individual"); - - if (inset_individual_faces) { - attribute_domain = ATTR_DOMAIN_FACE; - } - - const float default_distance = 0; - GVArray_Typed distance_attribute = params.get_input_attribute( - "Distance", mesh_component, attribute_domain, default_distance); - VArray_Span distance{distance_attribute}; - - const float default_inset = 0; - GVArray_Typed inset_attribute = params.get_input_attribute( - "Inset", mesh_component, attribute_domain, default_inset); - VArray_Span inset{inset_attribute}; - - bool *selection_top_faces_out = nullptr; - bool *selection_all_faces_out = nullptr; - - Mesh *result = extrude_mesh(input_mesh, - selection, - distance, - inset, - inset_individual_faces, - &selection_top_faces_out, - &selection_all_faces_out); - - const AttributeDomain result_face_domain = ATTR_DOMAIN_FACE; - std::string selection_top_faces_out_attribute_name = params.get_input("Top Face"); - std::string selection_side_faces_out_attribute_name = params.get_input( - "Side Face"); - geometry_set.replace_mesh(result); - - MeshComponent &result_mesh_component = geometry_set.get_component_for_write(); - if (!selection_top_faces_out_attribute_name.empty()) { - - OutputAttribute_Typed selection_top_faces_out_attribute = - result_mesh_component.attribute_try_get_for_output_only( - selection_top_faces_out_attribute_name, result_face_domain); - Span selection_faces_top_out_span(selection_top_faces_out, result->totpoly); - selection_top_faces_out_attribute->set_all(selection_faces_top_out_span); - selection_top_faces_out_attribute.save(); - } - if (!selection_side_faces_out_attribute_name.empty()) { - OutputAttribute_Typed selection_side_faces_out_attribute = - result_mesh_component.attribute_try_get_for_output_only( - selection_side_faces_out_attribute_name, result_face_domain); - for (const int i : selection_side_faces_out_attribute->index_range()) { - if (selection_top_faces_out[i]) { - selection_all_faces_out[i] = false; - } - } - Span selection_faces_sides_out_span(selection_all_faces_out, result->totpoly); - selection_side_faces_out_attribute->set_all(selection_faces_sides_out_span); - selection_side_faces_out_attribute.save(); - } - MEM_freeN(selection_top_faces_out); - MEM_freeN(selection_all_faces_out); - } - - params.set_output("Geometry", std::move(geometry_set)); -} -} // namespace blender::nodes - -void register_node_type_geo_extrude() -{ - static bNodeType ntype; - - geo_node_type_base(&ntype, GEO_NODE_EXTRUDE, "Extrude", NODE_CLASS_GEOMETRY, 0); - node_type_socket_templates(&ntype, geo_node_extrude_in, geo_node_extrude_out); - node_type_init(&ntype, geo_node_extrude_init); - node_type_update(&ntype, geo_node_extrude_update); - ntype.draw_buttons = geo_node_extrude_layout; - ntype.geometry_node_execute = blender::nodes::geo_node_extrude_exec; - nodeRegisterType(&ntype); -} diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_inset.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_inset.cc new file mode 100644 index 00000000000..461e2303b95 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_inset.cc @@ -0,0 +1,215 @@ +/* + * 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 "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "BKE_mesh.h" +#include "BKE_node.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "bmesh.h" +#include "bmesh_tools.h" + +#include "node_geometry_util.hh" + +static bNodeSocketTemplate geo_node_mesh_inset_in[] = { + {SOCK_GEOMETRY, N_("Geometry")}, + {SOCK_STRING, N_("Distance")}, + {SOCK_FLOAT, N_("Distance"), 0.0f, 0, 0, 0, FLT_MIN, FLT_MAX, PROP_DISTANCE}, + {SOCK_STRING, N_("mesh_inset")}, + {SOCK_FLOAT, N_("mesh_inset"), 0.0f, 0, 0, 0, FLT_MIN, FLT_MAX, PROP_DISTANCE}, + {SOCK_BOOLEAN, N_("Individual")}, + {SOCK_STRING, N_("Selection")}, + {SOCK_STRING, N_("Top Face")}, + {SOCK_STRING, N_("Side Face")}, + {-1, ""}, +}; + +static bNodeSocketTemplate geo_node_mesh_inset_out[] = { + {SOCK_GEOMETRY, N_("Geometry")}, + {-1, ""}, +}; + +static void geo_node_mesh_inset_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiLayoutSetPropSep(layout, true); + uiLayoutSetPropDecorate(layout, false); + uiItemR(layout, ptr, "distance_mode", 0, nullptr, ICON_NONE); + uiItemR(layout, ptr, "mesh_inset_mode", 0, nullptr, ICON_NONE); +} + +static void geo_node_mesh_inset_init(bNodeTree *UNUSED(tree), bNode *node) +{ + node->custom1 = GEO_NODE_ATTRIBUTE_INPUT_FLOAT; + node->custom2 = GEO_NODE_ATTRIBUTE_INPUT_FLOAT; +} + +static void geo_node_mesh_inset_update(bNodeTree *UNUSED(ntree), bNode *node) +{ + blender::nodes::update_attribute_input_socket_availabilities( + *node, "Distance", (GeometryNodeAttributeInputMode)node->custom1, true); + blender::nodes::update_attribute_input_socket_availabilities( + *node, "mesh_inset", (GeometryNodeAttributeInputMode)node->custom2, true); +} + +using blender::Span; + +static Mesh *mesh_inset_mesh(const Mesh *mesh, + const Span selection, + const Span distance, + const Span mesh_inset, + const bool mesh_inset_individual_faces, + std::string selection_top_faces_out_attribute_name, + std::string selection_side_faces_out_attribute_name) +{ + const BMeshCreateParams bmesh_create_params = {true}; + const BMeshFromMeshParams bmesh_from_mesh_params = { + true, 0, 0, 0, {CD_MASK_ORIGINDEX, CD_MASK_ORIGINDEX, CD_MASK_ORIGINDEX}}; + + BMesh *bm = BKE_mesh_to_bmesh_ex(mesh, &bmesh_create_params, &bmesh_from_mesh_params); + + BM_select_faces(bm, selection.data()); + BMOperator op; + if (mesh_inset_individual_faces) { + BMO_op_initf(bm, + &op, + 0, + "inset_individual faces=%hf use_even_offset=%b thickness=%f depth=%f " + "thickness_array=%p depth_array=%p use_attributes=%b", + BM_ELEM_SELECT, + true, + mesh_inset[0], + distance[0], + mesh_inset.data(), + distance.data(), + true); + } + else { + BMO_op_initf(bm, + &op, + 0, + "inset_region faces=%hf use_boundary=%b use_even_offset=%b thickness=%f depth=%f " + "thickness_array=%p depth_array=%p use_attributes=%b", + BM_ELEM_SELECT, + true, + true, + mesh_inset[0], + distance[0], + mesh_inset.data(), + distance.data(), + true); + } + BM_tag_new_faces(bm, &op); + BM_untag_faces_by_tag(bm, BM_ELEM_SELECT); + + BMO_op_exec(bm, &op); + BMO_op_finish(bm, &op); + + CustomData_MeshMasks cd_mask_extra = {CD_MASK_ORIGINDEX, CD_MASK_ORIGINDEX, CD_MASK_ORIGINDEX}; + + Mesh *result = BKE_mesh_from_bmesh_for_eval_nomain(bm, &cd_mask_extra, mesh); + + MeshComponent component; + component.replace(result, GeometryOwnershipType::Editable); + + if (!selection_top_faces_out_attribute_name.empty()) { + blender::bke::OutputAttribute_Typed attribute = + component.attribute_try_get_for_output_only(selection_top_faces_out_attribute_name, + ATTR_DOMAIN_FACE); + BM_get_selected_faces(bm, attribute.as_span().data()); + attribute.save(); + } + + if (!selection_side_faces_out_attribute_name.empty()) { + blender::bke::OutputAttribute_Typed attribute = + component.attribute_try_get_for_output_only(selection_side_faces_out_attribute_name, + ATTR_DOMAIN_FACE); + BM_get_tagged_faces(bm, attribute.as_span().data()); + attribute.save(); + } + + BM_mesh_free(bm); + BKE_mesh_normals_tag_dirty(result); + + return result; +} + +namespace blender::nodes { +static void geo_node_mesh_inset_exec(GeoNodeExecParams params) +{ + GeometrySet geometry_set = params.extract_input("Geometry"); + + geometry_set = geometry_set_realize_instances(geometry_set); + + MeshComponent &mesh_component = geometry_set.get_component_for_write(); + if (mesh_component.has_mesh()) { + const bool default_selection = true; + GVArray_Typed selection_attribute = params.get_input_attribute( + "Selection", mesh_component, ATTR_DOMAIN_FACE, default_selection); + VArray_Span selection{selection_attribute}; + const Mesh *input_mesh = mesh_component.get_for_read(); + + AttributeDomain attribute_domain = ATTR_DOMAIN_POINT; + const bool mesh_inset_individual_faces = params.extract_input("Individual"); + + if (mesh_inset_individual_faces) { + attribute_domain = ATTR_DOMAIN_FACE; + } + + const float default_distance = 0; + GVArray_Typed distance_attribute = params.get_input_attribute( + "Distance", mesh_component, attribute_domain, default_distance); + VArray_Span distance{distance_attribute}; + + const float default_mesh_inset = 0; + GVArray_Typed mesh_inset_attribute = params.get_input_attribute( + "mesh_inset", mesh_component, attribute_domain, default_mesh_inset); + VArray_Span mesh_inset{mesh_inset_attribute}; + + std::string selection_top_faces_out_attribute_name = params.get_input("Top Face"); + std::string selection_side_faces_out_attribute_name = params.get_input( + "Side Face"); + + Mesh *result = mesh_inset_mesh(input_mesh, + selection, + distance, + mesh_inset, + mesh_inset_individual_faces, + selection_top_faces_out_attribute_name, + selection_side_faces_out_attribute_name); + + geometry_set.replace_mesh(result); + } + + params.set_output("Geometry", std::move(geometry_set)); +} +} // namespace blender::nodes + +void register_node_type_geo_mesh_inset() +{ + static bNodeType ntype; + + geo_node_type_base(&ntype, GEO_NODE_MESH_INSET, "MeshInset", NODE_CLASS_GEOMETRY, 0); + node_type_socket_templates(&ntype, geo_node_mesh_inset_in, geo_node_mesh_inset_out); + node_type_init(&ntype, geo_node_mesh_inset_init); + node_type_update(&ntype, geo_node_mesh_inset_update); + ntype.draw_buttons = geo_node_mesh_inset_layout; + ntype.geometry_node_execute = blender::nodes::geo_node_mesh_inset_exec; + nodeRegisterType(&ntype); +} -- cgit v1.2.3