diff options
Diffstat (limited to 'source/blender/modifiers/intern/MOD_weightvg_util.c')
-rw-r--r-- | source/blender/modifiers/intern/MOD_weightvg_util.c | 248 |
1 files changed, 248 insertions, 0 deletions
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..1fe1a96c2e5 --- /dev/null +++ b/source/blender/modifiers/intern/MOD_weightvg_util.c @@ -0,0 +1,248 @@ +/* +* $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; + char add2vg = do_add; + 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; + } + add2vg = 0; + break; + } + } + + /* If the vert wasn’t in the deform group, add it if needed! + */ + if (add2vg && 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++; + } + } +} + |