Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/modifiers/intern/MOD_weightvgmix.cc')
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgmix.cc524
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..d860e93d535
--- /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 * /*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 * /*scene*/, ModifierData *md, bool /*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 * /*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,
+};