/* SPDX-License-Identifier: GPL-2.0-or-later */ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "BKE_mesh.h" #include "node_geometry_util.hh" namespace blender::nodes::node_geo_input_mesh_face_neighbors_cc { static void node_declare(NodeDeclarationBuilder &b) { b.add_output(N_("Vertex Count")) .field_source() .description(N_("Number of edges or points in the face")); b.add_output(N_("Face Count")) .field_source() .description(N_("Number of faces which share an edge with the face")); } static VArray construct_neighbor_count_gvarray(const MeshComponent &component, const eAttrDomain domain) { const Mesh *mesh = component.get_for_read(); if (mesh == nullptr) { return {}; } Array edge_count(mesh->totedge, 0); for (const int i : IndexRange(mesh->totloop)) { edge_count[mesh->mloop[i].e]++; } Array poly_count(mesh->totpoly, 0); for (const int poly_num : IndexRange(mesh->totpoly)) { MPoly &poly = mesh->mpoly[poly_num]; for (const int loop_num : IndexRange(poly.loopstart, poly.totloop)) { poly_count[poly_num] += edge_count[mesh->mloop[loop_num].e] - 1; } } return component.attributes()->adapt_domain( VArray::ForContainer(std::move(poly_count)), ATTR_DOMAIN_FACE, domain); } class FaceNeighborCountFieldInput final : public GeometryFieldInput { public: FaceNeighborCountFieldInput() : GeometryFieldInput(CPPType::get(), "Face Neighbor Count Field") { category_ = Category::Generated; } GVArray get_varray_for_context(const GeometryComponent &component, const eAttrDomain domain, IndexMask UNUSED(mask)) const final { if (component.type() == GEO_COMPONENT_TYPE_MESH) { const MeshComponent &mesh_component = static_cast(component); return construct_neighbor_count_gvarray(mesh_component, domain); } return {}; } uint64_t hash() const override { /* Some random constant hash. */ return 823543774; } bool is_equal_to(const fn::FieldNode &other) const override { return dynamic_cast(&other) != nullptr; } }; static VArray construct_vertex_count_gvarray(const MeshComponent &component, const eAttrDomain domain) { const Mesh *mesh = component.get_for_read(); if (mesh == nullptr) { return {}; } return component.attributes()->adapt_domain( VArray::ForFunc(mesh->totpoly, [mesh](const int i) -> float { return mesh->mpoly[i].totloop; }), ATTR_DOMAIN_FACE, domain); } class FaceVertexCountFieldInput final : public GeometryFieldInput { public: FaceVertexCountFieldInput() : GeometryFieldInput(CPPType::get(), "Vertex Count Field") { category_ = Category::Generated; } GVArray get_varray_for_context(const GeometryComponent &component, const eAttrDomain domain, IndexMask UNUSED(mask)) const final { if (component.type() == GEO_COMPONENT_TYPE_MESH) { const MeshComponent &mesh_component = static_cast(component); return construct_vertex_count_gvarray(mesh_component, domain); } return {}; } uint64_t hash() const override { /* Some random constant hash. */ return 236235463634; } bool is_equal_to(const fn::FieldNode &other) const override { return dynamic_cast(&other) != nullptr; } }; static void node_geo_exec(GeoNodeExecParams params) { Field vertex_count_field{std::make_shared()}; Field neighbor_count_field{std::make_shared()}; params.set_output("Vertex Count", std::move(vertex_count_field)); params.set_output("Face Count", std::move(neighbor_count_field)); } } // namespace blender::nodes::node_geo_input_mesh_face_neighbors_cc void register_node_type_geo_input_mesh_face_neighbors() { namespace file_ns = blender::nodes::node_geo_input_mesh_face_neighbors_cc; static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_INPUT_MESH_FACE_NEIGHBORS, "Face Neighbors", NODE_CLASS_INPUT); node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); }