diff options
author | Hans Goudey <h.goudey@me.com> | 2022-10-07 00:05:56 +0300 |
---|---|---|
committer | Hans Goudey <h.goudey@me.com> | 2022-10-07 00:08:07 +0300 |
commit | 406a98aff893570eef1f2d217b87a5997a7a60d6 (patch) | |
tree | 39af815c97e1d9ec3b1cb5658186a8981e383a73 /source/blender/modifiers/intern/MOD_weightvgmix.cc | |
parent | 53d937a1700021e0cb7a52aa0c45da0014974e81 (diff) |
Cleanup: Move eight modifier files to C++
In preparation for moving mesh runtime data to C++.
Diffstat (limited to 'source/blender/modifiers/intern/MOD_weightvgmix.cc')
-rw-r--r-- | source/blender/modifiers/intern/MOD_weightvgmix.cc | 524 |
1 files changed, 524 insertions, 0 deletions
diff --git a/source/blender/modifiers/intern/MOD_weightvgmix.cc b/source/blender/modifiers/intern/MOD_weightvgmix.cc new file mode 100644 index 00000000000..720f9fac948 --- /dev/null +++ b/source/blender/modifiers/intern/MOD_weightvgmix.cc @@ -0,0 +1,524 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2011 by Bastien Montagne. All rights reserved. */ + +/** \file + * \ingroup modifiers + */ + +#include "BLI_utildefines.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" + +#include "BLT_translation.h" + +#include "DNA_defaults.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" +#include "DNA_screen_types.h" + +#include "BKE_context.h" +#include "BKE_customdata.h" +#include "BKE_deform.h" +#include "BKE_lib_query.h" +#include "BKE_mesh.h" +#include "BKE_modifier.h" +#include "BKE_screen.h" +#include "BKE_texture.h" /* Texture masking. */ + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "RNA_access.h" +#include "RNA_prototypes.h" + +#include "DEG_depsgraph_build.h" +#include "DEG_depsgraph_query.h" + +#include "MEM_guardedalloc.h" + +#include "MOD_modifiertypes.h" +#include "MOD_ui_common.h" +#include "MOD_util.h" +#include "MOD_weightvg_util.h" + +/** + * This mixes the old weight with the new weight factor. + */ +static float mix_weight(float weight, float weight2, char mix_mode) +{ +#if 0 + /* + * XXX Don't know why, but the switch version takes many CPU time, + * and produces lag in realtime playback... + */ + switch (mix_mode) { + case MOD_WVG_MIX_ADD: + return (weight + weight2); + case MOD_WVG_MIX_SUB: + return (weight - weight2); + case MOD_WVG_MIX_MUL: + return (weight * weight2); + case MOD_WVG_MIX_DIV: + /* Avoid dividing by zero (or really small values). */ + if (0.0 <= weight2 < MOD_WVG_ZEROFLOOR) { + weight2 = MOD_WVG_ZEROFLOOR; + } + else if (-MOD_WVG_ZEROFLOOR < weight2) { + weight2 = -MOD_WVG_ZEROFLOOR; + } + return (weight / weight2); + case MOD_WVG_MIX_DIF: + return (weight < weight2 ? weight2 - weight : weight - weight2); + case MOD_WVG_MIX_AVG: + return (weight + weight2) / 2.0; + case MOD_WVG_MIX_SET: + default: + return weight2; + } +#endif + if (mix_mode == MOD_WVG_MIX_SET) { + return weight2; + } + if (mix_mode == MOD_WVG_MIX_ADD) { + return (weight + weight2); + } + if (mix_mode == MOD_WVG_MIX_SUB) { + return (weight - weight2); + } + if (mix_mode == MOD_WVG_MIX_MUL) { + return (weight * weight2); + } + if (mix_mode == MOD_WVG_MIX_DIV) { + /* Avoid dividing by zero (or really small values). */ + if (weight2 < 0.0f && weight2 > -MOD_WVG_ZEROFLOOR) { + weight2 = -MOD_WVG_ZEROFLOOR; + } + else if (weight2 >= 0.0f && weight2 < MOD_WVG_ZEROFLOOR) { + weight2 = MOD_WVG_ZEROFLOOR; + } + return (weight / weight2); + } + if (mix_mode == MOD_WVG_MIX_DIF) { + return (weight < weight2 ? weight2 - weight : weight - weight2); + } + if (mix_mode == MOD_WVG_MIX_AVG) { + return (weight + weight2) * 0.5f; + } + if (mix_mode == MOD_WVG_MIX_MIN) { + return (weight < weight2 ? weight : weight2); + } + if (mix_mode == MOD_WVG_MIX_MAX) { + return (weight > weight2 ? weight : weight2); + } + + return weight2; +} + +/************************************** + * Modifiers functions. * + **************************************/ +static void initData(ModifierData *md) +{ + WeightVGMixModifierData *wmd = (WeightVGMixModifierData *)md; + + BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(wmd, modifier)); + + MEMCPY_STRUCT_AFTER(wmd, DNA_struct_default_get(WeightVGMixModifierData), modifier); +} + +static void requiredDataMask(ModifierData *md, CustomData_MeshMasks *r_cddata_masks) +{ + WeightVGMixModifierData *wmd = (WeightVGMixModifierData *)md; + + /* We need vertex groups! */ + r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; + + /* Ask for UV coordinates if we need them. */ + if (wmd->mask_tex_mapping == MOD_DISP_MAP_UV) { + r_cddata_masks->fmask |= CD_MASK_MTFACE; + } + + /* No need to ask for CD_PREVIEW_MLOOPCOL... */ +} + +static bool dependsOnTime(Scene *UNUSED(scene), ModifierData *md) +{ + WeightVGMixModifierData *wmd = (WeightVGMixModifierData *)md; + + if (wmd->mask_texture) { + return BKE_texture_dependsOnTime(wmd->mask_texture); + } + return false; +} + +static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData) +{ + WeightVGMixModifierData *wmd = (WeightVGMixModifierData *)md; + + walk(userData, ob, (ID **)&wmd->mask_texture, IDWALK_CB_USER); + walk(userData, ob, (ID **)&wmd->mask_tex_map_obj, IDWALK_CB_NOP); +} + +static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void *userData) +{ + walk(userData, ob, md, "mask_texture"); +} + +static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx) +{ + WeightVGMixModifierData *wmd = (WeightVGMixModifierData *)md; + bool need_transform_relation = false; + + if (wmd->mask_texture != nullptr) { + DEG_add_generic_id_relation(ctx->node, &wmd->mask_texture->id, "WeightVGMix Modifier"); + + if (wmd->mask_tex_map_obj != nullptr && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) { + MOD_depsgraph_update_object_bone_relation( + ctx->node, wmd->mask_tex_map_obj, wmd->mask_tex_map_bone, "WeightVGMix Modifier"); + need_transform_relation = true; + } + else if (wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL) { + need_transform_relation = true; + } + } + + if (need_transform_relation) { + DEG_add_depends_on_transform_relation(ctx->node, "WeightVGMix Modifier"); + } +} + +static bool isDisabled(const Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams)) +{ + WeightVGMixModifierData *wmd = (WeightVGMixModifierData *)md; + /* If no vertex group, bypass. */ + return (wmd->defgrp_name_a[0] == '\0'); +} + +static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) +{ + BLI_assert(mesh != nullptr); + + WeightVGMixModifierData *wmd = (WeightVGMixModifierData *)md; + + MDeformWeight **dw1, **tdw1, **dw2, **tdw2; + float *org_w; + float *new_w; + int *tidx, *indices = nullptr; + int index_num = 0; + int i; + const bool invert_vgroup_mask = (wmd->flag & MOD_WVG_MIX_INVERT_VGROUP_MASK) != 0; + const bool do_normalize = (wmd->flag & MOD_WVG_MIX_WEIGHTS_NORMALIZE) != 0; + + /* + * Note that we only invert the weight values within provided vgroups, the selection based on + * which vertex is affected because it belongs or not to a group remains unchanged. + * In other words, vertices not belonging to a group won't be affected, even though their + * inverted 'virtual' weight would be 1.0f. + */ + const bool invert_vgroup_a = (wmd->flag & MOD_WVG_MIX_INVERT_VGROUP_A) != 0; + const bool invert_vgroup_b = (wmd->flag & MOD_WVG_MIX_INVERT_VGROUP_B) != 0; + + /* Flags. */ +#if 0 + const bool do_prev = (wmd->modifier.mode & eModifierMode_DoWeightPreview) != 0; +#endif + + /* Get number of verts. */ + const int verts_num = mesh->totvert; + + /* Check if we can just return the original mesh. + * Must have verts and therefore verts assigned to vgroups to do anything useful! + */ + if ((verts_num == 0) || BLI_listbase_is_empty(&mesh->vertex_group_names)) { + return mesh; + } + + /* Get vgroup idx from its name. */ + const int defgrp_index = BKE_id_defgroup_name_index(&mesh->id, wmd->defgrp_name_a); + if (defgrp_index == -1) { + return mesh; + } + /* Get second vgroup idx from its name, if given. */ + int defgrp_index_other = -1; + if (wmd->defgrp_name_b[0] != '\0') { + defgrp_index_other = BKE_id_defgroup_name_index(&mesh->id, wmd->defgrp_name_b); + if (defgrp_index_other == -1) { + return mesh; + } + } + + const bool has_mdef = CustomData_has_layer(&mesh->vdata, CD_MDEFORMVERT); + /* If no vertices were ever added to an object's vgroup, dvert might be nullptr. */ + if (!has_mdef) { + /* If not affecting all vertices, just return. */ + if (wmd->mix_set != MOD_WVG_SET_ALL) { + return mesh; + } + } + + MDeformVert *dvert = BKE_mesh_deform_verts_for_write(mesh); + + /* Ultimate security check. */ + if (!dvert) { + return mesh; + } + + /* Find out which vertices to work on. */ + tidx = static_cast<int *>(MEM_malloc_arrayN(verts_num, sizeof(int), __func__)); + tdw1 = static_cast<MDeformWeight **>( + MEM_malloc_arrayN(verts_num, sizeof(MDeformWeight *), __func__)); + tdw2 = static_cast<MDeformWeight **>( + MEM_malloc_arrayN(verts_num, sizeof(MDeformWeight *), __func__)); + switch (wmd->mix_set) { + case MOD_WVG_SET_A: + /* All vertices in first vgroup. */ + for (i = 0; i < verts_num; i++) { + MDeformWeight *dw = BKE_defvert_find_index(&dvert[i], defgrp_index); + if (dw) { + tdw1[index_num] = dw; + tdw2[index_num] = (defgrp_index_other >= 0) ? + BKE_defvert_find_index(&dvert[i], defgrp_index_other) : + nullptr; + tidx[index_num++] = i; + } + } + break; + case MOD_WVG_SET_B: + /* All vertices in second vgroup. */ + for (i = 0; i < verts_num; i++) { + MDeformWeight *dw = (defgrp_index_other >= 0) ? + BKE_defvert_find_index(&dvert[i], defgrp_index_other) : + nullptr; + if (dw) { + tdw1[index_num] = BKE_defvert_find_index(&dvert[i], defgrp_index); + tdw2[index_num] = dw; + tidx[index_num++] = i; + } + } + break; + case MOD_WVG_SET_OR: + /* All vertices in one vgroup or the other. */ + for (i = 0; i < verts_num; i++) { + MDeformWeight *adw = BKE_defvert_find_index(&dvert[i], defgrp_index); + MDeformWeight *bdw = (defgrp_index_other >= 0) ? + BKE_defvert_find_index(&dvert[i], defgrp_index_other) : + nullptr; + if (adw || bdw) { + tdw1[index_num] = adw; + tdw2[index_num] = bdw; + tidx[index_num++] = i; + } + } + break; + case MOD_WVG_SET_AND: + /* All vertices in both vgroups. */ + for (i = 0; i < verts_num; i++) { + MDeformWeight *adw = BKE_defvert_find_index(&dvert[i], defgrp_index); + MDeformWeight *bdw = (defgrp_index_other >= 0) ? + BKE_defvert_find_index(&dvert[i], defgrp_index_other) : + nullptr; + if (adw && bdw) { + tdw1[index_num] = adw; + tdw2[index_num] = bdw; + tidx[index_num++] = i; + } + } + break; + case MOD_WVG_SET_ALL: + default: + /* Use all vertices. */ + for (i = 0; i < verts_num; i++) { + tdw1[i] = BKE_defvert_find_index(&dvert[i], defgrp_index); + tdw2[i] = (defgrp_index_other >= 0) ? + BKE_defvert_find_index(&dvert[i], defgrp_index_other) : + nullptr; + } + index_num = -1; + break; + } + if (index_num == 0) { + /* Use no vertices! Hence, return org data. */ + MEM_freeN(tdw1); + MEM_freeN(tdw2); + MEM_freeN(tidx); + return mesh; + } + if (index_num != -1) { + indices = static_cast<int *>(MEM_malloc_arrayN(index_num, sizeof(int), __func__)); + memcpy(indices, tidx, sizeof(int) * index_num); + dw1 = static_cast<MDeformWeight **>( + MEM_malloc_arrayN(index_num, sizeof(MDeformWeight *), __func__)); + memcpy(dw1, tdw1, sizeof(MDeformWeight *) * index_num); + MEM_freeN(tdw1); + dw2 = static_cast<MDeformWeight **>( + MEM_malloc_arrayN(index_num, sizeof(MDeformWeight *), __func__)); + memcpy(dw2, tdw2, sizeof(MDeformWeight *) * index_num); + MEM_freeN(tdw2); + } + else { + /* Use all vertices. */ + index_num = verts_num; + /* Just copy MDeformWeight pointers arrays, they will be freed at the end. */ + dw1 = tdw1; + dw2 = tdw2; + } + MEM_freeN(tidx); + + org_w = static_cast<float *>(MEM_malloc_arrayN(index_num, sizeof(float), __func__)); + new_w = static_cast<float *>(MEM_malloc_arrayN(index_num, sizeof(float), __func__)); + + /* Mix weights. */ + for (i = 0; i < index_num; i++) { + float weight2; + if (invert_vgroup_a) { + org_w[i] = 1.0f - (dw1[i] ? dw1[i]->weight : wmd->default_weight_a); + } + else { + org_w[i] = dw1[i] ? dw1[i]->weight : wmd->default_weight_a; + } + if (invert_vgroup_b) { + weight2 = 1.0f - (dw2[i] ? dw2[i]->weight : wmd->default_weight_b); + } + else { + weight2 = dw2[i] ? dw2[i]->weight : wmd->default_weight_b; + } + + new_w[i] = mix_weight(org_w[i], weight2, wmd->mix_mode); + } + + /* Do masking. */ + Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); + weightvg_do_mask(ctx, + index_num, + indices, + org_w, + new_w, + ctx->object, + mesh, + wmd->mask_constant, + wmd->mask_defgrp_name, + scene, + wmd->mask_texture, + wmd->mask_tex_use_channel, + wmd->mask_tex_mapping, + wmd->mask_tex_map_obj, + wmd->mask_tex_map_bone, + wmd->mask_tex_uvlayer_name, + invert_vgroup_mask); + + /* Update (add to) vgroup. + * XXX Depending on the MOD_WVG_SET_xxx option chosen, we might have to add vertices to vgroup. + */ + weightvg_update_vg(dvert, + defgrp_index, + dw1, + index_num, + indices, + org_w, + true, + -FLT_MAX, + false, + 0.0f, + do_normalize); + + /* If weight preview enabled... */ +#if 0 /* XXX Currently done in mod stack :/ */ + if (do_prev) { + DM_update_weight_mcol(ob, dm, 0, org_w, index_num, indices); + } +#endif + + /* Freeing stuff. */ + MEM_freeN(org_w); + MEM_freeN(new_w); + MEM_freeN(dw1); + MEM_freeN(dw2); + MEM_SAFE_FREE(indices); + + mesh->runtime.is_original_bmesh = false; + + /* Return the vgroup-modified mesh. */ + return mesh; +} + +static void panel_draw(const bContext *UNUSED(C), Panel *panel) +{ + uiLayout *layout = panel->layout; + + PointerRNA ob_ptr; + PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr); + + uiLayoutSetPropSep(layout, true); + + modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group_a", "invert_vertex_group_a", nullptr); + modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group_b", "invert_vertex_group_b", IFACE_("B")); + + uiItemS(layout); + + uiItemR(layout, ptr, "default_weight_a", 0, nullptr, ICON_NONE); + uiItemR(layout, ptr, "default_weight_b", 0, IFACE_("B"), ICON_NONE); + + uiItemS(layout); + + uiItemR(layout, ptr, "mix_set", 0, nullptr, ICON_NONE); + uiItemR(layout, ptr, "mix_mode", 0, nullptr, ICON_NONE); + + uiItemR(layout, ptr, "normalize", 0, nullptr, ICON_NONE); + + modifier_panel_end(layout, ptr); +} + +static void influence_panel_draw(const bContext *C, Panel *panel) +{ + uiLayout *layout = panel->layout; + + PointerRNA ob_ptr; + PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr); + + weightvg_ui_common(C, &ob_ptr, ptr, layout); +} + +static void panelRegister(ARegionType *region_type) +{ + PanelType *panel_type = modifier_panel_register( + region_type, eModifierType_WeightVGMix, panel_draw); + modifier_subpanel_register( + region_type, "influence", "Influence", nullptr, influence_panel_draw, panel_type); +} + +ModifierTypeInfo modifierType_WeightVGMix = { + /* name */ N_("VertexWeightMix"), + /* structName */ "WeightVGMixModifierData", + /* structSize */ sizeof(WeightVGMixModifierData), + /* srna */ &RNA_VertexWeightMixModifier, + /* type */ eModifierTypeType_NonGeometrical, + /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping | + eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_UsesPreview, + /* icon */ ICON_MOD_VERTEX_WEIGHT, + + /* copyData */ BKE_modifier_copydata_generic, + + /* deformVerts */ nullptr, + /* deformMatrices */ nullptr, + /* deformVertsEM */ nullptr, + /* deformMatricesEM */ nullptr, + /* modifyMesh */ modifyMesh, + /* modifyGeometrySet */ nullptr, + + /* initData */ initData, + /* requiredDataMask */ requiredDataMask, + /* freeData */ nullptr, + /* isDisabled */ isDisabled, + /* updateDepsgraph */ updateDepsgraph, + /* dependsOnTime */ dependsOnTime, + /* dependsOnNormals */ nullptr, + /* foreachIDLink */ foreachIDLink, + /* foreachTexLink */ foreachTexLink, + /* freeRuntimeData */ nullptr, + /* panelRegister */ panelRegister, + /* blendWrite */ nullptr, + /* blendRead */ nullptr, +}; |