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:
authorBastien Montagne <montagne29@wanadoo.fr>2011-07-25 19:27:01 +0400
committerBastien Montagne <montagne29@wanadoo.fr>2011-07-25 19:27:01 +0400
commit1e2e08085319712183aa8171c003c851f7707ce1 (patch)
tree158e9de5b7fa7f53746fc8c48dedb363725ce240 /source/blender/modifiers
parent110f6d81ec27c8620ef693a743de18b6aaafeb44 (diff)
Adding WeightVG modifiers code. Still some points to tweak, though.
NOTE : Haven’t yet tested build with scons, will do asap (unless someone else does :) ).
Diffstat (limited to 'source/blender/modifiers')
-rw-r--r--source/blender/modifiers/CMakeLists.txt5
-rw-r--r--source/blender/modifiers/MOD_modifiertypes.h3
-rw-r--r--source/blender/modifiers/intern/MOD_util.c3
-rw-r--r--source/blender/modifiers/intern/MOD_weightvg_util.c246
-rw-r--r--source/blender/modifiers/intern/MOD_weightvg_util.h82
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgedit.c343
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgmix.c433
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgproximity.c512
8 files changed, 1627 insertions, 0 deletions
diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt
index d1f153265ac..4c3a7423aba 100644
--- a/source/blender/modifiers/CMakeLists.txt
+++ b/source/blender/modifiers/CMakeLists.txt
@@ -80,11 +80,16 @@ set(SRC
intern/MOD_uvproject.c
intern/MOD_warp.c
intern/MOD_wave.c
+ intern/MOD_weightvg_util.c
+ intern/MOD_weightvgedit.c
+ intern/MOD_weightvgmix.c
+ intern/MOD_weightvgproximity.c
MOD_modifiertypes.h
intern/MOD_boolean_util.h
intern/MOD_fluidsim_util.h
intern/MOD_util.h
+ intern/MOD_weightvg_util.h
)
if(WITH_MOD_BOOLEAN)
diff --git a/source/blender/modifiers/MOD_modifiertypes.h b/source/blender/modifiers/MOD_modifiertypes.h
index 4e44a226c64..0ba906a433b 100644
--- a/source/blender/modifiers/MOD_modifiertypes.h
+++ b/source/blender/modifiers/MOD_modifiertypes.h
@@ -72,6 +72,9 @@ extern ModifierTypeInfo modifierType_ShapeKey;
extern ModifierTypeInfo modifierType_Solidify;
extern ModifierTypeInfo modifierType_Screw;
extern ModifierTypeInfo modifierType_Warp;
+extern ModifierTypeInfo modifierType_WeightVGEdit;
+extern ModifierTypeInfo modifierType_WeightVGMix;
+extern ModifierTypeInfo modifierType_WeightVGProximity;
/* MOD_util.c */
void modifier_type_init(ModifierTypeInfo *types[]);
diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c
index e9b835eab81..26e9d48cd0a 100644
--- a/source/blender/modifiers/intern/MOD_util.c
+++ b/source/blender/modifiers/intern/MOD_util.c
@@ -295,5 +295,8 @@ void modifier_type_init(ModifierTypeInfo *types[])
INIT_TYPE(Solidify);
INIT_TYPE(Screw);
INIT_TYPE(Warp);
+ INIT_TYPE(WeightVGEdit);
+ INIT_TYPE(WeightVGMix);
+ INIT_TYPE(WeightVGProximity);
#undef INIT_TYPE
}
diff --git a/source/blender/modifiers/intern/MOD_weightvg_util.c b/source/blender/modifiers/intern/MOD_weightvg_util.c
new file mode 100644
index 00000000000..c18fceb1e3f
--- /dev/null
+++ b/source/blender/modifiers/intern/MOD_weightvg_util.c
@@ -0,0 +1,246 @@
+/*
+* $Id$
+*
+* ***** BEGIN GPL LICENSE BLOCK *****
+*
+* 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.
+*
+* The Original Code is Copyright (C) 2011 by Bastien Montagne.
+* All rights reserved.
+*
+* Contributor(s): None yet.
+*
+* ***** END GPL LICENSE BLOCK *****
+*
+*/
+
+/*
+ * XXX I’d like to make modified weights visible in WeightPaint mode,
+ * but couldn’t figure a way to do this…
+ * Maybe this will need changes in mesh_calc_modifiers (DerivedMesh.c)?
+ * Or the WeightPaint mode code itself?
+ */
+
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+#include "BLI_string.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_cdderivedmesh.h"
+#include "BKE_deform.h"
+#include "BKE_mesh.h"
+#include "BKE_modifier.h"
+#include "BKE_texture.h" /* Texture masking. */
+
+#include "depsgraph_private.h"
+#include "MEM_guardedalloc.h"
+#include "MOD_util.h"
+#include "MOD_weightvg_util.h"
+#include "RE_shader_ext.h" /* Texture masking. */
+
+/* Applies new_w weights to org_w ones, using either a texture, vgroup or constant value as factor.
+ * Return values are in org_w.
+ * If indices is not NULL, it must be a table of same length as org_w and new_w, mapping to the real
+ * vertex index (in case the weight tables do not cover the whole vertices...).
+ * XXX The standard “factor” value is assumed in [0.0, 1.0] range. Else, weird results might appear.
+ */
+void weightvg_do_mask(int num, int *indices, float *org_w, float *new_w, Object *ob,
+ DerivedMesh *dm, float fact, const char *defgrp_name, Tex *texture,
+ int tex_use_channel, int tex_mapping, Object *tex_map_object,
+ const char *tex_uvlayer_name) {
+ int ref_didx;
+ MDeformVert *dvert = NULL;
+ int i;
+
+ /* If influence factor is null, nothing to do! */
+ if (fact == 0.0) return;
+
+ /* If we want to mask vgroup weights from a texture. */
+ if (texture) {
+ /* The texture coordinates. */
+ float (*tex_co)[3];
+ /* See mapping note below… */
+ MappingInfoModifierData t_map;
+ float (*v_co)[3];
+
+ /* Use new generic get_texture_coords, but do not modify our DNA struct for it…
+ * XXX Why use a ModifierData stuff here ? Why not a simple, generic struct for parameters ?
+ * What e.g. if a modifier wants to use several textures ?
+ * Why use only v_co, and not MVert (or both) ?
+ */
+ t_map.texture = texture;
+ t_map.map_object = tex_map_object;
+ BLI_strncpy(t_map.uvlayer_name, tex_uvlayer_name, sizeof(t_map.uvlayer_name));
+ t_map.texmapping = tex_mapping;
+ v_co = MEM_mallocN(sizeof(*v_co) * num, "WeightVG Modifier, TEX mode, v_co");
+ dm->getVertCos(dm, v_co);
+ tex_co = MEM_callocN(sizeof(*tex_co) * num, "WeightVG Modifier, TEX mode, tex_co");
+ get_texture_coords(&t_map, ob, dm, v_co, tex_co, num);
+ MEM_freeN(v_co);
+
+ /* For each weight (vertex), make the mix between org and new weights. */
+ for(i = 0; i < num; ++i) {
+ int idx = indices ? indices[i] : i;
+ TexResult texres;
+ float h, s, v; /* For HSV color space. */
+
+ texres.nor = NULL;
+ get_texture_value(texture, tex_co[idx], &texres);
+ /* Get the good channel value… */
+ switch(tex_use_channel) {
+ case MOD_WVG_MASK_TEX_USE_INT:
+ org_w[i] = (new_w[i] * texres.tin * fact) + (org_w[i] * (1.0 - (texres.tin*fact)));
+ break;
+ case MOD_WVG_MASK_TEX_USE_RED:
+ org_w[i] = (new_w[i] * texres.tr * fact) + (org_w[i] * (1.0 - (texres.tr*fact)));
+ break;
+ case MOD_WVG_MASK_TEX_USE_GREEN:
+ org_w[i] = (new_w[i] * texres.tg * fact) + (org_w[i] * (1.0 - (texres.tg*fact)));
+ break;
+ case MOD_WVG_MASK_TEX_USE_BLUE:
+ org_w[i] = (new_w[i] * texres.tb * fact) + (org_w[i] * (1.0 - (texres.tb*fact)));
+ break;
+ case MOD_WVG_MASK_TEX_USE_HUE:
+ rgb_to_hsv(texres.tr, texres.tg, texres.tb, &h, &s, &v);
+ org_w[i] = (new_w[i] * h * fact) + (org_w[i] * (1.0 - (h*fact)));
+ break;
+ case MOD_WVG_MASK_TEX_USE_SAT:
+ rgb_to_hsv(texres.tr, texres.tg, texres.tb, &h, &s, &v);
+ org_w[i] = (new_w[i] * s * fact) + (org_w[i] * (1.0 - (s*fact)));
+ break;
+ case MOD_WVG_MASK_TEX_USE_VAL:
+ rgb_to_hsv(texres.tr, texres.tg, texres.tb, &h, &s, &v);
+ org_w[i] = (new_w[i] * v * fact) + (org_w[i] * (1.0 - (v*fact)));
+ break;
+ case MOD_WVG_MASK_TEX_USE_ALPHA:
+ org_w[i] = (new_w[i] * texres.ta * fact) + (org_w[i] * (1.0 - (texres.ta*fact)));
+ break;
+ default:
+ org_w[i] = (new_w[i] * texres.tin * fact) + (org_w[i] * (1.0 - (texres.tin*fact)));
+ break;
+ }
+ }
+
+ MEM_freeN(tex_co);
+ return;
+ }
+
+ /* Check whether we want to set vgroup weights from a constant weight factor or a vertex
+ * group.
+ */
+ /* Get vgroup idx from its name. */
+ ref_didx = defgroup_name_index(ob, defgrp_name);
+ /* Proceed only if vgroup is valid, else use constant factor. */
+ if (ref_didx >= 0) {
+ /* Get actual dverts (ie vertex group data). */
+ dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
+ /* Proceed only if vgroup is valid, else assume factor = O. */
+ if (dvert == NULL) return;
+
+ /* For each weight (vertex), make the mix between org and new weights. */
+ for (i = 0; i < num; i++) {
+ int idx = indices ? indices[i] : i;
+ int j;
+ for (j = 0; j < dvert[idx].totweight; j++) {
+ if(dvert[idx].dw[j].def_nr == ref_didx) {
+ float f = dvert[idx].dw[j].weight * fact;
+ org_w[i] = (new_w[i] * f) + (org_w[i] * (1.0-f));
+ break;
+ }
+ }
+ /* If that vertex is not in ref vgroup, assume null factor, and hence do nothing! */
+ }
+ return;
+ }
+
+ /* Default "influence" behavior. */
+ /* For each weight (vertex), make the mix between org and new weights. */
+ for (i = 0; i < num; i++) {
+ org_w[i] = (new_w[i] * fact) + (org_w[i] * (1.0-fact));
+ }
+}
+
+/* Applies weights to given vgroup (defgroup), and optionnaly add/remove vertices from the group.
+ * If indices is not NULL, it must be a table of same length as weights, mapping to the real
+ * vertex index (in case the weight table does not cover the whole vertices...).
+ */
+void weightvg_update_vg(MDeformVert *dvert, int defgrp_idx, int num, int *indices,
+ float *weights, int do_add, float add_thresh, int do_rem,
+ float rem_thresh){
+ int i;
+
+ for (i = 0; i < num; i++) {
+ int j;
+ float w = weights[i];
+ MDeformVert *dv = &dvert[indices ? indices[i] : i];
+ MDeformWeight *newdw;
+
+ /* Let’s first check to see if this vert is already in the weight group – if so
+ * let’s update it, or remove it if needed.
+ */
+ for (j = 0; j < dv->totweight; j++) {
+ /* If this weight corresponds to the deform group, update the value or,
+ * if lower than rem_threshold, remove the vertex from the vgroup.
+ */
+ if (dv->dw[j].def_nr == defgrp_idx) {
+ /* Remove the vertex from this vgroup if needed. */
+ if (do_rem && w < rem_thresh) {
+ dv->totweight--;
+ /* If there are still other deform weights attached to this vert then remove
+ * this deform weight, and reshuffle the others.
+ */
+ if(dv->totweight) {
+ newdw = MEM_mallocN(sizeof(MDeformWeight)*(dv->totweight), "deformWeight");
+ if(dv->dw){
+ memcpy(newdw, dv->dw, sizeof(MDeformWeight)*j);
+ memcpy(newdw+j, dv->dw+j+1, sizeof(MDeformWeight)*(dv->totweight-j));
+ MEM_freeN(dv->dw);
+ }
+ dv->dw = newdw;
+ }
+ /* If there are no other deform weights left then just remove this one. */
+ else {
+ MEM_freeN(dv->dw);
+ dv->dw = NULL;
+ }
+ }
+ /* Else, just set the new computed weight. */
+ else
+ dv->dw[j].weight = w;
+ break;
+ }
+ continue;
+ }
+
+ /* If the vert wasn’t in the deform group, add it if needed!
+ */
+ if (do_add && w > add_thresh) {
+ newdw = MEM_callocN(sizeof(MDeformWeight)*(dv->totweight+1), "WeightVGEdit Modifier, deformWeight");
+ if(dv->dw) {
+ memcpy(newdw, dv->dw, sizeof(MDeformWeight)*dv->totweight);
+ MEM_freeN(dv->dw);
+ }
+ dv->dw = newdw;
+ dv->dw[dv->totweight].weight = w;
+ dv->dw[dv->totweight].def_nr = defgrp_idx;
+ dv->totweight++;
+ }
+ }
+}
+
diff --git a/source/blender/modifiers/intern/MOD_weightvg_util.h b/source/blender/modifiers/intern/MOD_weightvg_util.h
new file mode 100644
index 00000000000..1bd40e3879f
--- /dev/null
+++ b/source/blender/modifiers/intern/MOD_weightvg_util.h
@@ -0,0 +1,82 @@
+/*
+* $Id$
+*
+* ***** BEGIN GPL LICENSE BLOCK *****
+*
+* 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.
+*
+* The Original Code is Copyright (C) 2011 by Bastien Montagne.
+* All rights reserved.
+*
+* Contributor(s): None yet.
+*
+* ***** END GPL LICENSE BLOCK *****
+*
+*/
+
+/** \file blender/modifiers/intern/MOD_util.h
+ * \ingroup modifiers
+ */
+
+
+#ifndef MOD_WEIGHTVG_UTIL_H
+#define MOD_WEIGHTVG_UTIL_H
+
+/* so modifier types match their defines */
+#include "MOD_modifiertypes.h"
+
+struct Tex;
+struct DerivedMesh;
+struct Object;
+/*struct ModifierData;
+struct MappingInfoModifierData;*/
+
+/*
+ * XXX I’d like to make modified weights visible in WeightPaint mode,
+ * but couldn’t figure a way to do this…
+ * Maybe this will need changes in mesh_calc_modifiers (DerivedMesh.c)?
+ * Or the WeightPaint mode code itself?
+ */
+
+/**************************************
+ * Util functions. *
+ **************************************/
+
+/* We cannot divide by zero (what a surprise…).
+ * So if -MOD_WEIGHTVGROUP_DIVMODE_ZEROFLOOR < weightf < MOD_WEIGHTVGROUP_DIVMODE_ZEROFLOOR,
+ * we clamp weightf to this value (or its negative version).
+ * Also used to avoid null power factor.
+ */
+#define MOD_WVG_ZEROFLOOR 1.0e-32f
+
+/* Applies new_w weights to org_w ones, using either a texture, vgroup or constant value as factor.
+ * Return values are in org_w.
+ * If indices is not NULL, it must be a table of same length as org_w and new_w, mapping to the real
+ * vertex index (in case the weight tables do not cover the whole vertices...).
+ * XXX The standard “factor” value is assumed in [0.0, 1.0] range. Else, weird results might appear.
+ */
+void weightvg_do_mask(int num, int *indices, float *org_w, float *new_w, Object *ob,
+ struct DerivedMesh *dm, float fact, const char *defgrp_name, Tex *texture,
+ int tex_use_channel, int tex_mapping, Object *tex_map_object,
+ const char *tex_uvlayer_name);
+
+/* Applies weights to given vgroup (defgroup), and optionnaly add/remove vertices from the group.
+ * If indices is not NULL, it must be a table of same length as weights, mapping to the real
+ * vertex index (in case the weight table does not cover the whole vertices...).
+ */
+void weightvg_update_vg(MDeformVert *dvert, int defgrp_idx, int num, int *indices, float *weights,
+ int do_add, float add_thresh, int do_rem, float rem_thresh);
+
+#endif /* MOD_WEIGHTVG_UTIL_H */
diff --git a/source/blender/modifiers/intern/MOD_weightvgedit.c b/source/blender/modifiers/intern/MOD_weightvgedit.c
new file mode 100644
index 00000000000..c8d7ab52ce8
--- /dev/null
+++ b/source/blender/modifiers/intern/MOD_weightvgedit.c
@@ -0,0 +1,343 @@
+/*
+* $Id$
+*
+* ***** BEGIN GPL LICENSE BLOCK *****
+*
+* 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.
+*
+* The Original Code is Copyright (C) 2011 by Bastien Montagne.
+* All rights reserved.
+*
+* Contributor(s): None yet.
+*
+* ***** END GPL LICENSE BLOCK *****
+*
+*/
+
+/*
+ * XXX I’d like to make modified weights visible in WeightPaint mode,
+ * but couldn’t figure a way to do this…
+ * Maybe this will need changes in mesh_calc_modifiers (DerivedMesh.c)?
+ * Or the WeightPaint mode code itself?
+ */
+
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+#include "BLI_string.h"
+
+#include "DNA_color_types.h" /* CurveMapping. */
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_cdderivedmesh.h"
+#include "BKE_colortools.h" /* CurveMapping. */
+#include "BKE_deform.h"
+#include "BKE_mesh.h"
+#include "BKE_modifier.h"
+#include "BKE_texture.h" /* Texture masking. */
+
+#include "depsgraph_private.h"
+#include "MEM_guardedalloc.h"
+#include "MOD_util.h"
+#include "MOD_weightvg_util.h"
+
+/**************************************
+ * Modifiers functions. *
+ **************************************/
+static void initData(ModifierData *md)
+{
+ WeightVGEditModifierData *wmd = (WeightVGEditModifierData*) md;
+ wmd->edit_flags = MOD_WVG_EDIT_CLAMP;
+ wmd->default_weight = 0.0f;
+
+ wmd->map_org_min = 0.0f;
+ wmd->map_org_max = 1.0f;
+ wmd->map_new_min = 0.0f;
+ wmd->map_new_max = 1.0f;
+ wmd->cmap_curve = curvemapping_add(1, 0.0, 0.0, 1.0, 1.0);
+ curvemapping_initialize(wmd->cmap_curve);
+
+ wmd->clamp_min_weight = 0.0f;
+ wmd->clamp_max_weight = 1.0f;
+
+ wmd->add_threshold = 0.01f;
+ wmd->rem_threshold = 0.01f;
+
+ wmd->mask_constant = 1.0f;
+ wmd->mask_tex_use_channel = MOD_WVG_MASK_TEX_USE_INT; /* Use intensity by default. */
+ wmd->mask_tex_mapping = MOD_DISP_MAP_LOCAL;
+}
+
+static void freeData(ModifierData *md)
+{
+ WeightVGEditModifierData *wmd = (WeightVGEditModifierData*) md;
+ curvemapping_free(wmd->cmap_curve);
+}
+
+static void copyData(ModifierData *md, ModifierData *target)
+{
+ WeightVGEditModifierData *wmd = (WeightVGEditModifierData*) md;
+ WeightVGEditModifierData *twmd = (WeightVGEditModifierData*) target;
+
+ BLI_strncpy(twmd->defgrp_name, wmd->defgrp_name, sizeof(twmd->defgrp_name));
+
+ twmd->edit_flags = wmd->edit_flags;
+ twmd->default_weight = wmd->default_weight;
+
+ twmd->map_org_min = wmd->map_org_min;
+ twmd->map_org_max = wmd->map_org_max;
+ twmd->map_new_min = wmd->map_new_min;
+ twmd->map_new_max = wmd->map_new_max;
+ twmd->cmap_curve = curvemapping_copy(wmd->cmap_curve);
+
+ twmd->clamp_min_weight = wmd->clamp_min_weight;
+ twmd->clamp_max_weight = wmd->clamp_max_weight;
+
+ twmd->add_threshold = wmd->add_threshold;
+ twmd->rem_threshold = wmd->rem_threshold;
+
+ twmd->mask_constant = wmd->mask_constant;
+ BLI_strncpy(twmd->mask_defgrp_name, wmd->mask_defgrp_name, sizeof(twmd->mask_defgrp_name));
+ twmd->mask_texture = wmd->mask_texture;
+ twmd->mask_tex_use_channel = wmd->mask_tex_use_channel;
+ twmd->mask_tex_mapping = wmd->mask_tex_mapping;
+ twmd->mask_tex_map_obj = wmd->mask_tex_map_obj;
+ BLI_strncpy(twmd->mask_tex_uvlayer_name, wmd->mask_tex_uvlayer_name,
+ sizeof(twmd->mask_tex_uvlayer_name));
+}
+
+static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
+{
+ WeightVGEditModifierData *wmd = (WeightVGEditModifierData*) md;
+ CustomDataMask dataMask = 0;
+
+ /* We need vertex groups! */
+ dataMask |= CD_MASK_MDEFORMVERT;
+
+ /* Ask for UV coordinates if we need them. */
+ if(wmd->mask_tex_mapping == MOD_DISP_MAP_UV)
+ dataMask |= CD_MASK_MTFACE;
+
+ return dataMask;
+}
+
+static int dependsOnTime(ModifierData *md)
+{
+ WeightVGEditModifierData *wmd = (WeightVGEditModifierData*) md;
+
+ if(wmd->mask_texture)
+ return BKE_texture_dependsOnTime(wmd->mask_texture);
+ return 0;
+}
+
+static void foreachObjectLink(ModifierData *md, Object *ob,
+ void (*walk)(void *userData, Object *ob, Object **obpoin),
+ void *userData)
+{
+ WeightVGEditModifierData *wmd = (WeightVGEditModifierData*) md;
+ walk(userData, ob, &wmd->mask_tex_map_obj);
+}
+
+static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
+{
+ WeightVGEditModifierData *wmd = (WeightVGEditModifierData*) md;
+
+ walk(userData, ob, (ID **)&wmd->mask_texture);
+
+ foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
+}
+
+static void updateDepgraph(ModifierData *md, DagForest *forest, struct Scene *UNUSED(scene),
+ Object *UNUSED(ob), DagNode *obNode)
+{
+ WeightVGEditModifierData *wmd = (WeightVGEditModifierData*) md;
+ DagNode *curNode;
+
+ if(wmd->mask_tex_map_obj && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) {
+ curNode = dag_get_node(forest, wmd->mask_tex_map_obj);
+
+ dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA|DAG_RL_OB_DATA,
+ "WeightVGEdit Modifier");
+ }
+
+ if(wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL)
+ dag_add_relation(forest, obNode, obNode, DAG_RL_DATA_DATA|DAG_RL_OB_DATA,
+ "WeightVGEdit Modifier");
+}
+
+static int isDisabled(ModifierData *md, int UNUSED(useRenderParams))
+{
+ WeightVGEditModifierData *wmd = (WeightVGEditModifierData*) md;
+ /* If no vertex group, bypass. */
+ return (wmd->defgrp_name == NULL);
+}
+
+static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData,
+ int UNUSED(useRenderParams), int UNUSED(isFinalCalc))
+{
+ WeightVGEditModifierData *wmd = (WeightVGEditModifierData*) md;
+ DerivedMesh *dm = derivedData;
+ DerivedMesh *ret;
+ MDeformVert *dvert = NULL;
+ float *org_w = NULL; /* Array original weights. */
+ float *new_w = NULL; /* Array new weights. */
+ int numVerts;
+ int defgrp_idx;
+ int i;
+ char rel_ret = 0; /* Boolean, whether we have to release ret dm or not, when not using it! */
+ float *mapf = NULL; /* Cache for mapping factors. */
+ /* Flags. */
+ char do_map = wmd->edit_flags & MOD_WVG_EDIT_MAP;
+ char do_cmap = wmd->edit_flags & MOD_WVG_EDIT_CMAP;
+ char do_rev = wmd->edit_flags & MOD_WVG_EDIT_REVERSE_WEIGHTS;
+ char do_add = wmd->edit_flags & MOD_WVG_EDIT_ADD2VG;
+ char do_rem = wmd->edit_flags & MOD_WVG_EDIT_REMFVG;
+ char do_clamp = wmd->edit_flags & MOD_WVG_EDIT_CLAMP;
+
+ /* Get number of verts. */
+ numVerts = dm->getNumVerts(dm);
+
+ /* Check if we can just return the original mesh.
+ * Must have verts and therefore verts assigned to vgroups to do anything useful!
+ */
+ if ((numVerts == 0) || (ob->defbase.first == NULL))
+ return dm;
+
+ /* Create a copy of our dmesh.
+ * TODO: This should be done only if needed, i.e. if dm has the org data !
+ */
+ if (1) {
+ /* XXX Seems to create problems with weightpaint mode... */
+// DM_set_only_copy(dm, CD_MASK_MDEFORMVERT); /* Only copy defgroup layer. */
+ ret = CDDM_copy(dm);
+ rel_ret = 1;
+ }
+ else
+ ret = dm;
+
+ /* Get vgroup idx from its name. */
+ defgrp_idx = defgroup_name_index(ob, wmd->defgrp_name);
+
+ /* Get actual dverts (ie vertex group data). */
+ if (defgrp_idx >= 0)
+ dvert = ret->getVertDataArray(ret, CD_MDEFORMVERT);
+ /* If no dverts, return unmodified data… */
+ if ((defgrp_idx < 0) || (dvert == NULL)) {
+ if (rel_ret)
+ ret->release(ret);
+ return dm;
+ }
+
+ /* Get org weights, assuming 0.0 for vertices not in given vgroup. */
+ org_w = MEM_mallocN(sizeof(float) * numVerts, "WeightVGEdit Modifier, org_w");
+ new_w = MEM_mallocN(sizeof(float) * numVerts, "WeightVGEdit Modifier, org_w");
+ for (i = 0; i < numVerts; i++) {
+ int j;
+ org_w[i] = new_w[i] = wmd->default_weight;
+ for (j = 0; j < dvert[i].totweight; j++) {
+ if(dvert[i].dw[j].def_nr == defgrp_idx) {
+ org_w[i] = new_w[i] = dvert[i].dw[j].weight;
+ break;
+ }
+ }
+ /* Do mapping. */
+ if (do_map) {
+ /* This mapping is a simple func: a*in + b.
+ * with a = (out_min - out_max)/(in_min - in_max)
+ * and b = out_max - a*in_max
+ * Note a and b are cached!
+ */
+ if (mapf == NULL) {
+ float denom = wmd->map_org_min - wmd->map_org_max;
+ mapf = MEM_mallocN(sizeof(float) * 2, "WeightVGEdit, mapf");
+ if (denom > 0.0 && denom < MOD_WVG_ZEROFLOOR)
+ denom = MOD_WVG_ZEROFLOOR;
+ else if (denom < 0.0 && denom > -MOD_WVG_ZEROFLOOR)
+ denom = -MOD_WVG_ZEROFLOOR;
+ mapf[0] = (wmd->map_new_min - wmd->map_new_max) / denom;
+ mapf[1] = wmd->map_new_max - (mapf[0] * wmd->map_org_max);
+ }
+ new_w[i] = (mapf[0] * new_w[i]) + mapf[1];
+ }
+ if (do_cmap)
+ new_w[i] = curvemapping_evaluateF(wmd->cmap_curve, 0, new_w[i]);
+ if (do_rev)
+ new_w[i] = (-1.0 * new_w[i]) + 1.0;
+ }
+
+ /* Do masking. */
+ weightvg_do_mask(numVerts, NULL, org_w, new_w, ob, ret, wmd->mask_constant,
+ wmd->mask_defgrp_name, wmd->mask_texture, wmd->mask_tex_use_channel,
+ wmd->mask_tex_mapping, wmd->mask_tex_map_obj, wmd->mask_tex_uvlayer_name);
+
+ /* Do clamping. */
+ if (do_clamp) {
+ for (i = 0; i < numVerts; i++)
+ CLAMP(org_w[i], wmd->clamp_min_weight, wmd->clamp_max_weight);
+ }
+
+ /* Update/add/remove from vgroup. */
+ weightvg_update_vg(dvert, defgrp_idx, numVerts, NULL, org_w, do_add, wmd->add_threshold,
+ do_rem, wmd->rem_threshold);
+
+ /* Freeing stuff. */
+ if (org_w)
+ MEM_freeN(org_w);
+ if (new_w)
+ MEM_freeN(new_w);
+ if (mapf)
+ MEM_freeN(mapf);
+
+ /* Return the vgroup-modified mesh. */
+ return ret;
+}
+
+static DerivedMesh *applyModifierEM(ModifierData *md, Object *ob,
+ struct EditMesh *UNUSED(editData),
+ DerivedMesh *derivedData)
+{
+ return applyModifier(md, ob, derivedData, 0, 1);
+}
+
+
+ModifierTypeInfo modifierType_WeightVGEdit = {
+ /* name */ "WeightVGEdit",
+ /* structName */ "WeightVGEditModifierData",
+ /* structSize */ sizeof(WeightVGEditModifierData),
+ /* type */ eModifierTypeType_Nonconstructive,
+ /* flags */ eModifierTypeFlag_AcceptsMesh
+ |eModifierTypeFlag_SupportsMapping
+ |eModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+ /* deformVerts */ NULL,
+ /* deformMatrices */ NULL,
+ /* deformVertsEM */ NULL,
+ /* deformMatricesEM */ NULL,
+ /* applyModifier */ applyModifier,
+ /* applyModifierEM */ applyModifierEM,
+ /* initData */ initData,
+ /* requiredDataMask */ requiredDataMask,
+ /* freeData */ freeData,
+ /* isDisabled */ isDisabled,
+ /* updateDepgraph */ updateDepgraph,
+ /* dependsOnTime */ dependsOnTime,
+ /* dependsOnNormals */ NULL,
+ /* foreachObjectLink */ foreachObjectLink,
+ /* foreachIDLink */ foreachIDLink,
+};
+
diff --git a/source/blender/modifiers/intern/MOD_weightvgmix.c b/source/blender/modifiers/intern/MOD_weightvgmix.c
new file mode 100644
index 00000000000..c4f107de72e
--- /dev/null
+++ b/source/blender/modifiers/intern/MOD_weightvgmix.c
@@ -0,0 +1,433 @@
+/*
+* $Id$
+*
+* ***** BEGIN GPL LICENSE BLOCK *****
+*
+* 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.
+*
+* The Original Code is Copyright (C) 2011 by Bastien Montagne.
+* All rights reserved.
+*
+* Contributor(s): None yet.
+*
+* ***** END GPL LICENSE BLOCK *****
+*
+*/
+
+/*
+ * XXX I’d like to make modified weights visible in WeightPaint mode,
+ * but couldn’t figure a way to do this…
+ * Maybe this will need changes in mesh_calc_modifiers (DerivedMesh.c)?
+ * Or the WeightPaint mode code itself?
+ */
+
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+#include "BLI_string.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_cdderivedmesh.h"
+#include "BKE_deform.h"
+#include "BKE_mesh.h"
+#include "BKE_modifier.h"
+#include "BKE_texture.h" /* Texture masking. */
+
+#include "depsgraph_private.h"
+#include "MEM_guardedalloc.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;
+ else if (mix_mode == MOD_WVG_MIX_ADD)
+ return (weight + weight2);
+ else if (mix_mode == MOD_WVG_MIX_SUB)
+ return (weight - weight2);
+ else if (mix_mode == MOD_WVG_MIX_MUL)
+ return (weight * weight2);
+ else if (mix_mode == MOD_WVG_MIX_DIV) {
+ /* Avoid dividing by zero (or really small values). */
+ if (weight2 < 0.0 && weight2 > -MOD_WVG_ZEROFLOOR)
+ weight2 = -MOD_WVG_ZEROFLOOR;
+ else if (weight2 >= 0.0 && weight2 < MOD_WVG_ZEROFLOOR)
+ weight2 = MOD_WVG_ZEROFLOOR;
+ return (weight / weight2);
+ }
+ else if (mix_mode == MOD_WVG_MIX_DIF)
+ return (weight < weight2 ? weight2 - weight : weight - weight2);
+ else if (mix_mode == MOD_WVG_MIX_AVG)
+ return (weight + weight2) / 2.0;
+ else return weight2;
+}
+
+/**************************************
+ * Modifiers functions. *
+ **************************************/
+static void initData(ModifierData *md)
+{
+ WeightVGMixModifierData *wmd = (WeightVGMixModifierData*) md;
+
+ wmd->default_weight = 0.0;
+ wmd->default_weight2 = 0.0;
+ wmd->mix_mode = MOD_WVG_MIX_SET;
+ wmd->mix_set = MOD_WVG_SET_INTER;
+
+ wmd->mask_constant = 1.0f;
+ wmd->mask_tex_use_channel = MOD_WVG_MASK_TEX_USE_INT; /* Use intensity by default. */
+ wmd->mask_tex_mapping = MOD_DISP_MAP_LOCAL;
+}
+
+static void copyData(ModifierData *md, ModifierData *target)
+{
+ WeightVGMixModifierData *wmd = (WeightVGMixModifierData*) md;
+ WeightVGMixModifierData *twmd = (WeightVGMixModifierData*) target;
+
+ BLI_strncpy(twmd->defgrp_name, wmd->defgrp_name, sizeof(twmd->defgrp_name));
+ BLI_strncpy(twmd->defgrp_name2, wmd->defgrp_name2, sizeof(twmd->defgrp_name2));
+ twmd->default_weight = wmd->default_weight;
+ twmd->default_weight2 = wmd->default_weight2;
+ twmd->mix_mode = wmd->mix_mode;
+ twmd->mix_set = wmd->mix_set;
+
+ twmd->mask_constant = wmd->mask_constant;
+ BLI_strncpy(twmd->mask_defgrp_name, wmd->mask_defgrp_name, sizeof(twmd->mask_defgrp_name));
+ twmd->mask_texture = wmd->mask_texture;
+ twmd->mask_tex_use_channel = wmd->mask_tex_use_channel;
+ twmd->mask_tex_mapping = wmd->mask_tex_mapping;
+ twmd->mask_tex_map_obj = wmd->mask_tex_map_obj;
+ BLI_strncpy(twmd->mask_tex_uvlayer_name, wmd->mask_tex_uvlayer_name,
+ sizeof(twmd->mask_tex_uvlayer_name));
+}
+
+static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
+{
+ WeightVGMixModifierData *wmd = (WeightVGMixModifierData*) md;
+ CustomDataMask dataMask = 0;
+
+ /* We need vertex groups! */
+ dataMask |= CD_MASK_MDEFORMVERT;
+
+ /* Ask for UV coordinates if we need them. */
+ if(wmd->mask_tex_mapping == MOD_DISP_MAP_UV)
+ dataMask |= CD_MASK_MTFACE;
+
+ return dataMask;
+}
+
+static int dependsOnTime(ModifierData *md)
+{
+ WeightVGMixModifierData *wmd = (WeightVGMixModifierData*) md;
+
+ if(wmd->mask_texture)
+ return BKE_texture_dependsOnTime(wmd->mask_texture);
+ return 0;
+}
+
+static void foreachObjectLink(ModifierData *md, Object *ob,
+ void (*walk)(void *userData, Object *ob, Object **obpoin),
+ void *userData)
+{
+ WeightVGMixModifierData *wmd = (WeightVGMixModifierData*) md;
+ walk(userData, ob, &wmd->mask_tex_map_obj);
+}
+
+static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
+{
+ WeightVGMixModifierData *wmd = (WeightVGMixModifierData*) md;
+
+ walk(userData, ob, (ID **)&wmd->mask_texture);
+
+ foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
+}
+
+static void updateDepgraph(ModifierData *md, DagForest *forest, struct Scene *UNUSED(scene),
+ Object *UNUSED(ob), DagNode *obNode)
+{
+ WeightVGMixModifierData *wmd = (WeightVGMixModifierData*) md;
+ DagNode *curNode;
+
+ if(wmd->mask_tex_map_obj && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) {
+ curNode = dag_get_node(forest, wmd->mask_tex_map_obj);
+
+ dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA|DAG_RL_OB_DATA,
+ "WeightVGMix Modifier");
+ }
+
+ if(wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL)
+ dag_add_relation(forest, obNode, obNode, DAG_RL_DATA_DATA|DAG_RL_OB_DATA,
+ "WeightVGMix Modifier");
+}
+
+static int isDisabled(ModifierData *md, int UNUSED(useRenderParams))
+{
+ WeightVGMixModifierData *wmd = (WeightVGMixModifierData*) md;
+ /* If no vertex group, bypass. */
+ return (wmd->defgrp_name == NULL);
+}
+
+static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData,
+ int UNUSED(useRenderParams), int UNUSED(isFinalCalc))
+{
+ WeightVGMixModifierData *wmd = (WeightVGMixModifierData*) md;
+ DerivedMesh *dm = derivedData;
+ DerivedMesh *ret;
+ MDeformVert *dvert = NULL;
+ int numVerts;
+ int defgrp_idx, defgrp_idx2 = -1;
+ float *org_w = NULL;
+ float *new_w = NULL;
+ int *tidx, *indices = NULL;
+ int numIdx = 0;
+ int i, j;
+ char rel_ret = 0; /* Boolean, whether we have to release ret dm or not, when not using it! */
+
+ /* Get number of verts. */
+ numVerts = dm->getNumVerts(dm);
+
+ /* Check if we can just return the original mesh.
+ * Must have verts and therefore verts assigned to vgroups to do anything useful!
+ */
+ if ((numVerts == 0) || (ob->defbase.first == NULL))
+ return dm;
+
+ /* Create a copy of our dmesh.
+ * TODO: This should be done only if needed !
+ */
+ if (1) {
+ /* XXX Seems to create problems with weightpaint mode... */
+// DM_set_only_copy(dm, CD_MASK_MDEFORMVERT); /* Only copy defgroup layer. */
+ ret = CDDM_copy(dm);
+ rel_ret = 1;
+ }
+ else
+ ret = dm;
+
+ /* Get first vgroup idx from its name. */
+ defgrp_idx = defgroup_name_index(ob, wmd->defgrp_name);
+
+ /* Get seconf vgroup idx from its name, if given. */
+ if (wmd->defgrp_name2)
+ defgrp_idx2 = defgroup_name_index(ob, wmd->defgrp_name2);
+
+ /* Get actual dverts (ie vertex group data). */
+ if (defgrp_idx >= 0)
+ dvert = ret->getVertDataArray(ret, CD_MDEFORMVERT);
+ /* If no dverts, return unmodified data… */
+ if ((defgrp_idx < 0) || (dvert == NULL)) {
+ if (rel_ret)
+ ret->release(ret);
+ return dm;
+ }
+
+ /* Find out which vertices to work on. */
+ tidx = MEM_mallocN(sizeof(int) * numVerts, "WeightVGMix Modifier, tidx");
+ switch (wmd->mix_set) {
+ case MOD_WVG_SET_ORG:
+ /* All vertices in first vgroup. */
+ for (i = 0; i < numVerts; i++) {
+ for (j = 0; j < dvert[i].totweight; j++) {
+ if(dvert[i].dw[j].def_nr == defgrp_idx) {
+ tidx[numIdx++] = i;
+ break;
+ }
+ }
+ }
+ break;
+ case MOD_WVG_SET_NEW:
+ /* All vertices in second vgroup. */
+ for (i = 0; i < numVerts; i++) {
+ for (j = 0; j < dvert[i].totweight; j++) {
+ if(dvert[i].dw[j].def_nr == defgrp_idx2) {
+ tidx[numIdx++] = i;
+ break;
+ }
+ }
+ }
+ break;
+ case MOD_WVG_SET_UNION:
+ /* All vertices in one vgroup or the other. */
+ for (i = 0; i < numVerts; i++) {
+ for (j = 0; j < dvert[i].totweight; j++) {
+ if(dvert[i].dw[j].def_nr == defgrp_idx || dvert[i].dw[j].def_nr == defgrp_idx2) {
+ tidx[numIdx++] = i;
+ break;
+ }
+ }
+ }
+ break;
+ case MOD_WVG_SET_INTER:
+ /* All vertices in both vgroups. */
+ for (i = 0; i < numVerts; i++) {
+ char idx1 = 0;
+ char idx2 = 0;
+ for (j = 0; j < dvert[i].totweight; j++) {
+ if(dvert[i].dw[j].def_nr == defgrp_idx) {
+ if (idx2) {
+ tidx[numIdx++] = i;
+ break;
+ }
+ else
+ idx1 = 1;
+ }
+ else if(dvert[i].dw[j].def_nr == defgrp_idx2) {
+ if (idx1) {
+ tidx[numIdx++] = i;
+ break;
+ }
+ else
+ idx2 = 1;
+ }
+ }
+ }
+ break;
+ case MOD_WVG_SET_ALL:
+ default:
+ /* Use all vertices, no need to do anything here. */
+ break;
+ }
+ if (numIdx) {
+ indices = MEM_mallocN(sizeof(int) * numIdx, "WeightVGMix Modifier, indices");
+ memcpy(indices, tidx, sizeof(int) * numIdx);
+ }
+ else
+ numIdx = numVerts;
+ MEM_freeN(tidx);
+
+ org_w = MEM_mallocN(sizeof(float) * numIdx, "WeightVGMix Modifier, org_w");
+ new_w = MEM_mallocN(sizeof(float) * numIdx, "WeightVGMix Modifier, new_w");
+
+ /* Mix weights. */
+ for (i = 0; i < numIdx; i++) {
+ float weight2 = 0.0;
+ char w1 = 0;
+ char w2 = 0;
+ int idx = indices ? indices[i] : i;
+ for (j = 0; j < dvert[idx].totweight; j++) {
+ if(dvert[idx].dw[j].def_nr == defgrp_idx) {
+ org_w[i] = dvert[idx].dw[j].weight;
+ w1 = 1;
+ if (w2)
+ break;
+ }
+ else if(dvert[idx].dw[j].def_nr == defgrp_idx2) {
+ weight2 = dvert[idx].dw[j].weight;
+ w2 = 1;
+ if (w1)
+ break;
+ }
+ }
+ if (w1 == 0)
+ org_w[i] = wmd->default_weight;
+ if (w2 == 0)
+ weight2 = wmd->default_weight2;
+ new_w[i] = mix_weight(org_w[i], weight2, wmd->mix_mode);
+ }
+
+ /* Do masking. */
+ weightvg_do_mask(numIdx, indices, org_w, new_w, ob, ret, wmd->mask_constant,
+ wmd->mask_defgrp_name, wmd->mask_texture, wmd->mask_tex_use_channel,
+ wmd->mask_tex_mapping, wmd->mask_tex_map_obj, wmd->mask_tex_uvlayer_name);
+
+ /* 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_idx, numIdx, indices, org_w, 1, -FLT_MAX, 0, 0.0f);
+
+ /* Freeing stuff. */
+ if (org_w)
+ MEM_freeN(org_w);
+ if (new_w)
+ MEM_freeN(new_w);
+ if (indices)
+ MEM_freeN(indices);
+
+ /* Return the vgroup-modified mesh. */
+ return ret;
+}
+
+static DerivedMesh *applyModifierEM(ModifierData *md, Object *ob,
+ struct EditMesh *UNUSED(editData),
+ DerivedMesh *derivedData)
+{
+ return applyModifier(md, ob, derivedData, 0, 1);
+}
+
+
+ModifierTypeInfo modifierType_WeightVGMix = {
+ /* name */ "WeightVGMix",
+ /* structName */ "WeightVGMixModifierData",
+ /* structSize */ sizeof(WeightVGMixModifierData),
+ /* type */ eModifierTypeType_Nonconstructive,
+ /* flags */ eModifierTypeFlag_AcceptsMesh
+ |eModifierTypeFlag_SupportsMapping
+ |eModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+ /* deformVerts */ NULL,
+ /* deformMatrices */ NULL,
+ /* deformVertsEM */ NULL,
+ /* deformMatricesEM */ NULL,
+ /* applyModifier */ applyModifier,
+ /* applyModifierEM */ applyModifierEM,
+ /* initData */ initData,
+ /* requiredDataMask */ requiredDataMask,
+ /* freeData */ NULL,
+ /* isDisabled */ isDisabled,
+ /* updateDepgraph */ updateDepgraph,
+ /* dependsOnTime */ dependsOnTime,
+ /* dependsOnNormals */ NULL,
+ /* foreachObjectLink */ foreachObjectLink,
+ /* foreachIDLink */ foreachIDLink,
+};
+
diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c
new file mode 100644
index 00000000000..7349d90c1ec
--- /dev/null
+++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c
@@ -0,0 +1,512 @@
+/*
+* $Id$
+*
+* ***** BEGIN GPL LICENSE BLOCK *****
+*
+* 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.
+*
+* The Original Code is Copyright (C) 2011 by Bastien Montagne.
+* All rights reserved.
+*
+* Contributor(s): None yet.
+*
+* ***** END GPL LICENSE BLOCK *****
+*
+*/
+
+/*
+ * XXX I’d like to make modified weights visible in WeightPaint mode,
+ * but couldn’t figure a way to do this…
+ * Maybe this will need changes in mesh_calc_modifiers (DerivedMesh.c)?
+ * Or the WeightPaint mode code itself?
+ */
+
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+#include "BLI_string.h"
+#include "BLI_editVert.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_cdderivedmesh.h"
+#include "BKE_deform.h"
+#include "BKE_mesh.h"
+#include "BKE_modifier.h"
+#include "BKE_shrinkwrap.h" /* For SpaceTransform stuff. */
+#include "BKE_texture.h" /* Texture masking. */
+
+#include "depsgraph_private.h"
+#include "MEM_guardedalloc.h"
+#include "MOD_util.h"
+#include "MOD_weightvg_util.h"
+
+/**************************************
+ * Util functions. *
+ **************************************/
+
+/* Util macro. */
+#define OUT_OF_MEMORY() ((void)printf("WeightVGProximity: Out of memory.\n"))
+
+/**
+ * Returns the squared distance between two given points.
+ */
+static float squared_dist(const float *a, const float *b)
+{
+ float tmp[3];
+ VECSUB(tmp, a, b);
+ return INPR(tmp, tmp);
+}
+
+/**
+ * Find nearest vertex and/or edge and/or face, for each vertex (adapted from shrinkwrap.c).
+ */
+static void get_vert2geom_distance(int numVerts, float (*v_cos)[3],
+ float *dist_v, float *dist_e, float *dist_f,
+ DerivedMesh *target, const SpaceTransform *loc2trgt)
+{
+ int i;
+ BVHTreeFromMesh treeData_v = NULL_BVHTreeFromMesh;
+ BVHTreeFromMesh treeData_e = NULL_BVHTreeFromMesh;
+ BVHTreeFromMesh treeData_f = NULL_BVHTreeFromMesh;
+ BVHTreeNearest nearest_v = NULL_BVHTreeNearest;
+ BVHTreeNearest nearest_e = NULL_BVHTreeNearest;
+ BVHTreeNearest nearest_f = NULL_BVHTreeNearest;
+
+ if (dist_v) {
+ /* Create a bvh-tree of the given target's verts. */
+ bvhtree_from_mesh_verts(&treeData_v, target, 0.0, 2, 6);
+ if(treeData_v.tree == NULL) {
+ OUT_OF_MEMORY();
+ return;
+ }
+ }
+ if (dist_e) {
+ /* Create a bvh-tree of the given target's edges. */
+ bvhtree_from_mesh_edges(&treeData_e, target, 0.0, 2, 6);
+ if(treeData_e.tree == NULL) {
+ OUT_OF_MEMORY();
+ return;
+ }
+ }
+ if (dist_f) {
+ /* Create a bvh-tree of the given target's faces. */
+ bvhtree_from_mesh_faces(&treeData_f, target, 0.0, 2, 6);
+ if(treeData_f.tree == NULL) {
+ OUT_OF_MEMORY();
+ return;
+ }
+ }
+
+ /* Setup nearest. */
+ nearest_v.index = nearest_e.index = nearest_f.index = -1;
+ /*nearest_v.dist = nearest_e.dist = nearest_f.dist = FLT_MAX;*/
+ /* Find the nearest vert/edge/face. */
+#ifndef __APPLE__
+#pragma omp parallel for default(none) private(i) firstprivate(nearest_v,nearest_e,nearest_f) \
+ shared(treeData_v,treeData_e,treeData_f,numVerts,v_cos,dist_v,dist_e, \
+ dist_f,loc2trgt) \
+ schedule(static)
+#endif
+ for (i = 0; i < numVerts; ++i) {
+ float tmp_co[3];
+
+ /* Convert the vertex to tree coordinates. */
+ VECCOPY(tmp_co, v_cos[i]);
+ space_transform_apply(loc2trgt, tmp_co);
+
+ /* Use local proximity heuristics (to reduce the nearest search).
+ *
+ * If we already had an hit before, we assume this vertex is going to have a close hit to
+ * that other vertex, so we can initiate the "nearest.dist" with the expected value to that
+ * last hit.
+ * This will lead in prunning of the search tree.
+ */
+ if (dist_v) {
+ nearest_v.dist = nearest_v.index != -1 ? squared_dist(tmp_co, nearest_v.co) : FLT_MAX;
+ /* Compute and store result. If invalid (-1 idx), keep FLT_MAX dist. */
+ BLI_bvhtree_find_nearest(treeData_v.tree, tmp_co, &nearest_v, treeData_v.nearest_callback, &treeData_v);
+ dist_v[i] = sqrtf(nearest_v.dist);
+ }
+ if (dist_e) {
+ nearest_e.dist = nearest_e.index != -1 ? squared_dist(tmp_co, nearest_e.co) : FLT_MAX;
+ /* Compute and store result. If invalid (-1 idx), keep FLT_MAX dist. */
+ BLI_bvhtree_find_nearest(treeData_e.tree, tmp_co, &nearest_e, treeData_e.nearest_callback, &treeData_e);
+ dist_e[i] = sqrtf(nearest_e.dist);
+ }
+ if (dist_f) {
+ nearest_f.dist = nearest_f.index != -1 ? squared_dist(tmp_co, nearest_f.co) : FLT_MAX;
+ /* Compute and store result. If invalid (-1 idx), keep FLT_MAX dist. */
+ BLI_bvhtree_find_nearest(treeData_f.tree, tmp_co, &nearest_f, treeData_f.nearest_callback, &treeData_f);
+ dist_f[i] = sqrtf(nearest_f.dist);
+ }
+ }
+
+ if (dist_v)
+ free_bvhtree_from_mesh(&treeData_v);
+ if (dist_e)
+ free_bvhtree_from_mesh(&treeData_e);
+ if (dist_f)
+ free_bvhtree_from_mesh(&treeData_f);
+}
+
+/**
+ * Returns the real distance between a vertex and another reference object.
+ * Note that it works in final world space (i.e. with constraints etc. applied).
+ */
+static void get_vert2ob_distance(int numVerts, float (*v_cos)[3], float *dist,
+ const Object* ob, const Object* obr)
+{
+ /* Vertex and ref object coordinates. */
+ float v_wco[3],
+ or_wco[3],
+ or_wro[3][3], /*unused*/
+ or_wsz[3]; /*unused*/
+ int i;
+
+ /* Get world-coordinates of the reference object (constraints and anim included).
+ * We also get rotation and scale, even though we do not want them…
+ */
+ mat4_to_loc_rot_size(or_wco, or_wro, or_wsz, (float (*)[4])obr->obmat);
+
+ for (i = 0; i < numVerts; i++) {
+ /* Get world-coordinates of the vertex (constraints and anim included). */
+ mul_v3_m4v3(v_wco, (float (*)[4])ob->obmat, v_cos[i]);
+ /* Return distance between both coordinates. */
+ dist[i] = len_v3v3(v_wco, or_wco);
+ }
+}
+
+/**
+ * Returns the real distance between an object and another reference object.
+ * Note that it works in final world space (i.e. with constraints etc. applied).
+ */
+static float get_ob2ob_distance(const Object* ob, const Object* obr)
+{
+ /* Both objects coordinates. */
+ float o_wco[3],
+ o_wro[3][3], /*unused*/
+ o_wsz[3], /*unused*/
+ or_wco[3],
+ or_wro[3][3],/*unused*/
+ or_wsz[3]; /*unused*/
+ /* Get world-coordinates of both objects (constraints and anim included).
+ * We also get rotation and scale, even though we do not want them…
+ */
+ mat4_to_loc_rot_size(o_wco, o_wro, o_wsz, (float (*)[4])ob->obmat);
+ mat4_to_loc_rot_size(or_wco, or_wro, or_wsz, (float (*)[4])obr->obmat);
+ /* Return distance between both coordinates. */
+ return len_v3v3(o_wco, or_wco);
+}
+
+/**************************************
+ * Modifiers functions. *
+ **************************************/
+static void initData(ModifierData *md)
+{
+ WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData*) md;
+
+ wmd->proximity_mode = MOD_WVG_PROXIMITY_OBJ2OBJDIST;
+ wmd->proximity_flags = MOD_WVG_PROXIMITY_O2VD_VERTS;
+
+ wmd->mask_constant = 1.0f;
+ wmd->mask_tex_use_channel = MOD_WVG_MASK_TEX_USE_INT; /* Use intensity by default. */
+ wmd->mask_tex_mapping = MOD_DISP_MAP_LOCAL;
+}
+
+static void copyData(ModifierData *md, ModifierData *target)
+{
+ WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData*) md;
+ WeightVGProximityModifierData *twmd = (WeightVGProximityModifierData*) target;
+
+ BLI_strncpy(twmd->defgrp_name, wmd->defgrp_name, sizeof(twmd->defgrp_name));
+ twmd->proximity_mode = wmd->proximity_mode;
+ twmd->proximity_flags = wmd->proximity_flags;
+ twmd->proximity_ob_target = wmd->proximity_ob_target;
+
+ twmd->mask_constant = wmd->mask_constant;
+ BLI_strncpy(twmd->mask_defgrp_name, wmd->mask_defgrp_name, sizeof(twmd->mask_defgrp_name));
+ twmd->mask_texture = wmd->mask_texture;
+ twmd->mask_tex_use_channel = wmd->mask_tex_use_channel;
+ twmd->mask_tex_mapping = wmd->mask_tex_mapping;
+ twmd->mask_tex_map_obj = wmd->mask_tex_map_obj;
+ BLI_strncpy(twmd->mask_tex_uvlayer_name, wmd->mask_tex_uvlayer_name,
+ sizeof(twmd->mask_tex_uvlayer_name));
+}
+
+static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
+{
+ WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData*) md;
+ CustomDataMask dataMask = 0;
+
+ /* We need vertex groups! */
+ dataMask |= CD_MASK_MDEFORMVERT;
+
+ /* Ask for UV coordinates if we need them. */
+ if(wmd->mask_tex_mapping == MOD_DISP_MAP_UV)
+ dataMask |= CD_MASK_MTFACE;
+
+ return dataMask;
+}
+
+static int dependsOnTime(ModifierData *md)
+{
+ WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData*) md;
+
+ if(wmd->mask_texture)
+ return BKE_texture_dependsOnTime(wmd->mask_texture);
+ return 0;
+}
+
+static void foreachObjectLink(ModifierData *md, Object *ob,
+ void (*walk)(void *userData, Object *ob, Object **obpoin),
+ void *userData)
+{
+ WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData*) md;
+ walk(userData, ob, &wmd->proximity_ob_target);
+ walk(userData, ob, &wmd->mask_tex_map_obj);
+}
+
+static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
+{
+ WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData*) md;
+
+ walk(userData, ob, (ID **)&wmd->mask_texture);
+
+ foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
+}
+
+static void updateDepgraph(ModifierData *md, DagForest *forest, struct Scene *UNUSED(scene),
+ Object *UNUSED(ob), DagNode *obNode)
+{
+ WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData*) md;
+ DagNode *curNode;
+
+ if (wmd->proximity_ob_target) {
+ curNode = dag_get_node(forest, wmd->proximity_ob_target);
+ dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA|DAG_RL_OB_DATA,
+ "WeightVGProximity Modifier");
+ }
+
+ if(wmd->mask_tex_map_obj && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) {
+ curNode = dag_get_node(forest, wmd->mask_tex_map_obj);
+
+ dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA|DAG_RL_OB_DATA,
+ "WeightVGProximity Modifier");
+ }
+
+ if(wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL)
+ dag_add_relation(forest, obNode, obNode, DAG_RL_DATA_DATA|DAG_RL_OB_DATA,
+ "WeightVGProximity Modifier");
+}
+
+static int isDisabled(ModifierData *md, int UNUSED(useRenderParams))
+{
+ WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData*) md;
+ /* If no vertex group, bypass. */
+ if (wmd->defgrp_name == NULL) return 1;
+ /* If no target object, bypass. */
+ return (wmd->proximity_ob_target == NULL);
+}
+
+static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData,
+ int UNUSED(useRenderParams), int UNUSED(isFinalCalc))
+{
+ WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData*) md;
+ DerivedMesh *dm = derivedData;
+ DerivedMesh *ret;
+ MDeformVert *dvert = NULL;
+ int numVerts;
+ float (*v_cos)[3] = NULL; /* The vertices coordinates. */
+ Object *obr; /* Our target object. */
+ int defgrp_idx;
+ float *tw = NULL;
+ float *org_w = NULL;
+ float *new_w =NULL;
+ int *tidx, *indices = NULL;
+ int numIdx = 0;
+ int i, j;
+ char rel_ret = 0; /* Boolean, whether we have to release ret dm or not, when not using it! */
+
+ /* Get number of verts. */
+ numVerts = dm->getNumVerts(dm);
+
+ /* Check if we can just return the original mesh.
+ * Must have verts and therefore verts assigned to vgroups to do anything useful!
+ */
+ if ((numVerts == 0) || (ob->defbase.first == NULL))
+ return dm;
+
+ /* Create a copy of our dmesh.
+ * TODO: This should be done only if needed !
+ */
+ if (1) {
+ /* XXX Seems to create problems with weightpaint mode... */
+// DM_set_only_copy(dm, CD_MASK_MDEFORMVERT); /* Only copy defgroup layer. */
+ ret = CDDM_copy(dm);
+ rel_ret = 1;
+ }
+ else
+ ret = dm;
+
+ /* Get vgroup idx from its name. */
+ defgrp_idx = defgroup_name_index(ob, wmd->defgrp_name);
+
+ /* Get actual dverts (ie vertex group data). */
+ if (defgrp_idx >= 0)
+ dvert = ret->getVertDataArray(ret, CD_MDEFORMVERT);
+ /* Get our target object. */
+ obr = wmd->proximity_ob_target;
+ /* If no dverts or target object, return unmodified data… */
+ if ((defgrp_idx < 0) || (dvert == NULL) || (!obr)) {
+ if (rel_ret)
+ ret->release(ret);
+ return dm;
+ }
+
+ /* Find out which vertices to work on (all vertices in vgroup), and get their relevant weight.
+ */
+ tidx = MEM_mallocN(sizeof(int) * numVerts, "WeightVGProximity Modifier, tidx");
+ tw = MEM_mallocN(sizeof(float) * numVerts, "WeightVGProximity Modifier, tw");
+ for (i = 0; i < numVerts; i++) {
+ for (j = 0; j < dvert[i].totweight; j++) {
+ if(dvert[i].dw[j].def_nr == defgrp_idx) {
+ tidx[numIdx] = i;
+ tw[numIdx++] = dvert[i].dw[j].weight;
+ break;
+ }
+ }
+ }
+ indices = MEM_mallocN(sizeof(int) * numIdx, "WeightVGProximity Modifier, indices");
+ memcpy(indices, tidx, sizeof(int) * numIdx);
+ org_w = MEM_mallocN(sizeof(float) * numIdx, "WeightVGProximity Modifier, org_w");
+ new_w = MEM_mallocN(sizeof(float) * numIdx, "WeightVGProximity Modifier, new_w");
+ memcpy(org_w, tw, sizeof(float) * numIdx);
+ MEM_freeN(tidx);
+ MEM_freeN(tw);
+
+ /* Get our vertex coordinates. */
+ v_cos = MEM_mallocN(sizeof(float[3]) * numIdx, "WeightVGProximity Modifier, v_cos");
+ for (i = 0; i < numIdx; i++)
+ ret->getVertCo(ret, indices[i], v_cos[i]);
+
+ /* Compute wanted distances. */
+ if (wmd->proximity_mode == MOD_WVG_PROXIMITY_OBJ2OBJDIST) {
+ float dist = get_ob2ob_distance(ob, obr);
+ for(i = 0; i < numIdx; i++)
+ new_w[i] = dist;
+ }
+ else if (wmd->proximity_mode == MOD_WVG_PROXIMITY_OBJ2VERTDIST) {
+ char use_trgt_verts = (wmd->proximity_flags & MOD_WVG_PROXIMITY_O2VD_VERTS);
+ char use_trgt_edges = (wmd->proximity_flags & MOD_WVG_PROXIMITY_O2VD_EDGES);
+ char use_trgt_faces = (wmd->proximity_flags & MOD_WVG_PROXIMITY_O2VD_FACES);
+
+ if (use_trgt_verts || use_trgt_edges || use_trgt_faces) {
+ DerivedMesh *target_dm = obr->derivedFinal;
+ if (!target_dm) {
+ if (ELEM3(obr->type, OB_CURVE, OB_SURF, OB_FONT))
+ target_dm = CDDM_from_curve(obr);
+ else if (obr->type == OB_MESH) {
+ Mesh *me = (Mesh*)obr->data;
+ if (me->edit_mesh)
+ target_dm = CDDM_from_editmesh((EditMesh*)me->edit_mesh, me);
+ else
+ target_dm = CDDM_from_mesh(me, obr);
+ }
+ }
+
+ /* We must check that we do have a valid target_dm! */
+ if (target_dm) {
+ SpaceTransform loc2trgt;
+ float *dists_v = use_trgt_verts ? MEM_mallocN(sizeof(float) * numIdx, "WeightVGProximity Modifier, dists_v") : NULL;
+ float *dists_e = use_trgt_edges ? MEM_mallocN(sizeof(float) * numIdx, "WeightVGProximity Modifier, dists_e") : NULL;
+ float *dists_f = use_trgt_faces ? MEM_mallocN(sizeof(float) * numIdx, "WeightVGProximity Modifier, dists_f") : NULL;
+
+ space_transform_setup(&loc2trgt, ob, obr);
+ get_vert2geom_distance(numIdx, v_cos, dists_v, dists_e, dists_f,
+ target_dm, &loc2trgt);
+ for(i = 0; i < numIdx; i++) {
+ new_w[i] = dists_v ? dists_v[i] : FLT_MAX;
+ new_w[i] = dists_e ? minf(dists_e[i], new_w[i]) : new_w[i];
+ new_w[i] = dists_f ? minf(dists_f[i], new_w[i]) : new_w[i];
+ }
+ }
+ /* Else, fall back to default obj2vert behavior. */
+ else
+ get_vert2ob_distance(numIdx, v_cos, new_w, ob, obr);
+ }
+ else
+ get_vert2ob_distance(numIdx, v_cos, new_w, ob, obr);
+ }
+
+ /* Do masking. */
+ weightvg_do_mask(numIdx, indices, org_w, new_w, ob, ret, wmd->mask_constant,
+ wmd->mask_defgrp_name, wmd->mask_texture, wmd->mask_tex_use_channel,
+ wmd->mask_tex_mapping, wmd->mask_tex_map_obj, wmd->mask_tex_uvlayer_name);
+
+ /* Update vgroup. Note we never add nor remove vertices from vgroup here. */
+ weightvg_update_vg(dvert, defgrp_idx, numIdx, indices, org_w, 0, 0.0f, 0, 0.0f);
+
+ /* Freeing stuff. */
+ if (org_w)
+ MEM_freeN(org_w);
+ if (new_w)
+ MEM_freeN(new_w);
+ if (indices)
+ MEM_freeN(indices);
+ if (v_cos)
+ MEM_freeN(v_cos);
+
+ /* Return the vgroup-modified mesh. */
+ return ret;
+}
+
+static DerivedMesh *applyModifierEM(ModifierData *md, Object *ob,
+ struct EditMesh *UNUSED(editData),
+ DerivedMesh *derivedData)
+{
+ return applyModifier(md, ob, derivedData, 0, 1);
+}
+
+
+ModifierTypeInfo modifierType_WeightVGProximity = {
+ /* name */ "WeightVGProximity",
+ /* structName */ "WeightVGProximityModifierData",
+ /* structSize */ sizeof(WeightVGProximityModifierData),
+ /* type */ eModifierTypeType_Nonconstructive,
+ /* flags */ eModifierTypeFlag_AcceptsMesh
+ |eModifierTypeFlag_SupportsMapping
+ |eModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+ /* deformVerts */ NULL,
+ /* deformMatrices */ NULL,
+ /* deformVertsEM */ NULL,
+ /* deformMatricesEM */ NULL,
+ /* applyModifier */ applyModifier,
+ /* applyModifierEM */ applyModifierEM,
+ /* initData */ initData,
+ /* requiredDataMask */ requiredDataMask,
+ /* freeData */ NULL,
+ /* isDisabled */ isDisabled,
+ /* updateDepgraph */ updateDepgraph,
+ /* dependsOnTime */ dependsOnTime,
+ /* dependsOnNormals */ NULL,
+ /* foreachObjectLink */ foreachObjectLink,
+ /* foreachIDLink */ foreachIDLink,
+};
+