diff options
Diffstat (limited to 'source/blender/modifiers/intern/MOD_weightvgedit.c')
-rw-r--r-- | source/blender/modifiers/intern/MOD_weightvgedit.c | 343 |
1 files changed, 343 insertions, 0 deletions
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, +}; + |