209 lines
6.3 KiB
C++
209 lines
6.3 KiB
C++
/* SPDX-FileCopyrightText: 2005 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
/** \file
|
|
* \ingroup modifiers
|
|
*
|
|
* Weld modifier: Remove doubles.
|
|
*/
|
|
|
|
/* TODOs:
|
|
* - Review weight and vertex color interpolation.;
|
|
*/
|
|
|
|
#include "BLI_utildefines.h"
|
|
|
|
#include "BLI_array.hh"
|
|
#include "BLI_index_range.hh"
|
|
#include "BLI_span.hh"
|
|
#include "BLI_vector.hh"
|
|
|
|
#include "BLT_translation.hh"
|
|
|
|
#include "DNA_defaults.h"
|
|
#include "DNA_mesh_types.h"
|
|
#include "DNA_meshdata_types.h"
|
|
#include "DNA_modifier_types.h"
|
|
#include "DNA_screen_types.h"
|
|
|
|
#include "BKE_context.hh"
|
|
#include "BKE_deform.hh"
|
|
#include "BKE_modifier.hh"
|
|
#include "BKE_screen.hh"
|
|
|
|
#include "UI_interface_layout.hh"
|
|
#include "UI_resources.hh"
|
|
|
|
#include "RNA_access.hh"
|
|
#include "RNA_prototypes.hh"
|
|
|
|
#include "MOD_modifiertypes.hh"
|
|
#include "MOD_ui_common.hh"
|
|
|
|
#include "GEO_mesh_merge_by_distance.hh"
|
|
|
|
using blender::Array;
|
|
using blender::IndexMask;
|
|
using blender::IndexMaskMemory;
|
|
using blender::Span;
|
|
using blender::Vector;
|
|
|
|
static Span<MDeformVert> get_vertex_group(const Mesh &mesh, const int defgrp_index)
|
|
{
|
|
if (defgrp_index == -1) {
|
|
return {};
|
|
}
|
|
return mesh.deform_verts();
|
|
}
|
|
|
|
static IndexMask selected_indices_from_vertex_group(Span<MDeformVert> vertex_group,
|
|
const int index,
|
|
const bool invert,
|
|
IndexMaskMemory &memory)
|
|
{
|
|
return IndexMask::from_predicate(
|
|
vertex_group.index_range(), blender::GrainSize(512), memory, [&](const int i) {
|
|
return (BKE_defvert_find_weight(&vertex_group[i], index) > 0.0f) != invert;
|
|
});
|
|
}
|
|
|
|
static Array<bool> selection_array_from_vertex_group(Span<MDeformVert> vertex_group,
|
|
const int index,
|
|
const bool invert)
|
|
{
|
|
Array<bool> selection(vertex_group.size());
|
|
for (const int i : vertex_group.index_range()) {
|
|
const bool found = BKE_defvert_find_weight(&vertex_group[i], index) > 0.0f;
|
|
selection[i] = (found != invert);
|
|
}
|
|
return selection;
|
|
}
|
|
|
|
static std::optional<Mesh *> calculate_weld(const Mesh &mesh, const WeldModifierData &wmd)
|
|
{
|
|
const int defgrp_index = BKE_id_defgroup_name_index(&mesh.id, wmd.defgrp_name);
|
|
Span<MDeformVert> vertex_group = get_vertex_group(mesh, defgrp_index);
|
|
const bool invert = (wmd.flag & MOD_WELD_INVERT_VGROUP) != 0;
|
|
|
|
if (wmd.mode == MOD_WELD_MODE_ALL) {
|
|
if (!vertex_group.is_empty()) {
|
|
IndexMaskMemory memory;
|
|
const IndexMask selected_indices = selected_indices_from_vertex_group(
|
|
vertex_group, defgrp_index, invert, memory);
|
|
return blender::geometry::mesh_merge_by_distance_all(
|
|
mesh, IndexMask(selected_indices), wmd.merge_dist);
|
|
}
|
|
return blender::geometry::mesh_merge_by_distance_all(
|
|
mesh, IndexMask(mesh.verts_num), wmd.merge_dist);
|
|
}
|
|
if (wmd.mode == MOD_WELD_MODE_CONNECTED) {
|
|
const bool only_loose_edges = (wmd.flag & MOD_WELD_LOOSE_EDGES) != 0;
|
|
if (!vertex_group.is_empty()) {
|
|
Array<bool> selection = selection_array_from_vertex_group(
|
|
vertex_group, defgrp_index, invert);
|
|
return blender::geometry::mesh_merge_by_distance_connected(
|
|
mesh, selection, wmd.merge_dist, only_loose_edges);
|
|
}
|
|
Array<bool> selection(mesh.verts_num, true);
|
|
return blender::geometry::mesh_merge_by_distance_connected(
|
|
mesh, selection, wmd.merge_dist, only_loose_edges);
|
|
}
|
|
|
|
BLI_assert_unreachable();
|
|
return nullptr;
|
|
}
|
|
|
|
static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext * /*ctx*/, Mesh *mesh)
|
|
{
|
|
const WeldModifierData &wmd = reinterpret_cast<WeldModifierData &>(*md);
|
|
|
|
std::optional<Mesh *> result = calculate_weld(*mesh, wmd);
|
|
if (!result) {
|
|
return mesh;
|
|
}
|
|
return *result;
|
|
}
|
|
|
|
static void init_data(ModifierData *md)
|
|
{
|
|
WeldModifierData *wmd = (WeldModifierData *)md;
|
|
|
|
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(wmd, modifier));
|
|
|
|
MEMCPY_STRUCT_AFTER(wmd, DNA_struct_default_get(WeldModifierData), modifier);
|
|
}
|
|
|
|
static void required_data_mask(ModifierData *md, CustomData_MeshMasks *r_cddata_masks)
|
|
{
|
|
WeldModifierData *wmd = (WeldModifierData *)md;
|
|
|
|
/* Ask for vertex-groups if we need them. */
|
|
if (wmd->defgrp_name[0] != '\0') {
|
|
r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
|
|
}
|
|
}
|
|
|
|
static void panel_draw(const bContext * /*C*/, Panel *panel)
|
|
{
|
|
uiLayout *layout = panel->layout;
|
|
|
|
PointerRNA ob_ptr;
|
|
PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
|
|
int weld_mode = RNA_enum_get(ptr, "mode");
|
|
|
|
layout->use_property_split_set(true);
|
|
|
|
layout->prop(ptr, "mode", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
|
layout->prop(ptr, "merge_threshold", UI_ITEM_NONE, IFACE_("Distance"), ICON_NONE);
|
|
if (weld_mode == MOD_WELD_MODE_CONNECTED) {
|
|
layout->prop(ptr, "loose_edges", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
|
}
|
|
modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", std::nullopt);
|
|
|
|
modifier_error_message_draw(layout, ptr);
|
|
}
|
|
|
|
static void panel_register(ARegionType *region_type)
|
|
{
|
|
modifier_panel_register(region_type, eModifierType_Weld, panel_draw);
|
|
}
|
|
|
|
ModifierTypeInfo modifierType_Weld = {
|
|
/*idname*/ "Weld",
|
|
/*name*/ N_("Weld"),
|
|
/*struct_name*/ "WeldModifierData",
|
|
/*struct_size*/ sizeof(WeldModifierData),
|
|
/*srna*/ &RNA_WeldModifier,
|
|
/*type*/ ModifierTypeType::Constructive,
|
|
/*flags*/
|
|
(eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping |
|
|
eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_EnableInEditmode |
|
|
eModifierTypeFlag_AcceptsCVs),
|
|
/*icon*/ ICON_AUTOMERGE_OFF, /* TODO: Use correct icon. */
|
|
|
|
/*copy_data*/ BKE_modifier_copydata_generic,
|
|
|
|
/*deform_verts*/ nullptr,
|
|
/*deform_matrices*/ nullptr,
|
|
/*deform_verts_EM*/ nullptr,
|
|
/*deform_matrices_EM*/ nullptr,
|
|
/*modify_mesh*/ modify_mesh,
|
|
/*modify_geometry_set*/ nullptr,
|
|
|
|
/*init_data*/ init_data,
|
|
/*required_data_mask*/ required_data_mask,
|
|
/*free_data*/ nullptr,
|
|
/*is_disabled*/ nullptr,
|
|
/*update_depsgraph*/ nullptr,
|
|
/*depends_on_time*/ nullptr,
|
|
/*depends_on_normals*/ nullptr,
|
|
/*foreach_ID_link*/ nullptr,
|
|
/*foreach_tex_link*/ nullptr,
|
|
/*free_runtime_data*/ nullptr,
|
|
/*panel_register*/ panel_register,
|
|
/*blend_write*/ nullptr,
|
|
/*blend_read*/ nullptr,
|
|
/*foreach_cache*/ nullptr,
|
|
};
|