vgroup_modifiers: Fixed last problems with WP mode, plus a small fix in weightvg_util.c.
[blender.git] / source / blender / modifiers / intern / MOD_weightvgedit.c
1 /*
2 * $Id$
3 *
4 * ***** BEGIN GPL LICENSE BLOCK *****
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software  Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 *
20 * The Original Code is Copyright (C) 2011 by Bastien Montagne.
21 * All rights reserved.
22 *
23 * Contributor(s): None yet.
24 *
25 * ***** END GPL LICENSE BLOCK *****
26 *
27 */
28
29 /*
30  * XXX I’d like to make modified weights visible in WeightPaint mode,
31  *     but couldn’t figure a way to do this…
32  *     Maybe this will need changes in mesh_calc_modifiers (DerivedMesh.c)?
33  *     Or the WeightPaint mode code itself?
34  */
35
36 #include "BLI_utildefines.h"
37 #include "BLI_math.h"
38 #include "BLI_string.h"
39
40 #include "DNA_color_types.h"      /* CurveMapping. */
41 #include "DNA_mesh_types.h"
42 #include "DNA_meshdata_types.h"
43 #include "DNA_modifier_types.h"
44 #include "DNA_object_types.h"
45
46 #include "BKE_cdderivedmesh.h"
47 #include "BKE_colortools.h"       /* CurveMapping. */
48 #include "BKE_deform.h"
49 #include "BKE_mesh.h"
50 #include "BKE_modifier.h"
51 #include "BKE_texture.h"          /* Texture masking. */
52
53 #include "depsgraph_private.h"
54 #include "MEM_guardedalloc.h"
55 #include "MOD_util.h"
56 #include "MOD_weightvg_util.h"
57
58 /**************************************
59  * Modifiers functions.               *
60  **************************************/
61 static void initData(ModifierData *md)
62 {
63         WeightVGEditModifierData *wmd = (WeightVGEditModifierData*) md;
64         wmd->edit_flags             = MOD_WVG_EDIT_CLAMP;
65         wmd->default_weight         = 0.0f;
66
67         wmd->map_org_min            = 0.0f;
68         wmd->map_org_max            = 1.0f;
69         wmd->map_new_min            = 0.0f;
70         wmd->map_new_max            = 1.0f;
71         wmd->cmap_curve             = curvemapping_add(1, 0.0, 0.0, 1.0, 1.0);
72         curvemapping_initialize(wmd->cmap_curve);
73
74         wmd->clamp_weight_min       = 0.0f;
75         wmd->clamp_weight_max       = 1.0f;
76
77         wmd->add_threshold          = 0.01f;
78         wmd->rem_threshold          = 0.01f;
79
80         wmd->mask_constant          = 1.0f;
81         wmd->mask_tex_use_channel   = MOD_WVG_MASK_TEX_USE_INT; /* Use intensity by default. */
82         wmd->mask_tex_mapping       = MOD_DISP_MAP_LOCAL;
83 }
84
85 static void freeData(ModifierData *md)
86 {
87         WeightVGEditModifierData *wmd = (WeightVGEditModifierData*) md;
88         curvemapping_free(wmd->cmap_curve);
89 }
90
91 static void copyData(ModifierData *md, ModifierData *target)
92 {
93         WeightVGEditModifierData *wmd  = (WeightVGEditModifierData*) md;
94         WeightVGEditModifierData *twmd = (WeightVGEditModifierData*) target;
95
96         BLI_strncpy(twmd->defgrp_name, wmd->defgrp_name, sizeof(twmd->defgrp_name));
97
98         twmd->edit_flags             = wmd->edit_flags;
99         twmd->default_weight         = wmd->default_weight;
100
101         twmd->map_org_min            = wmd->map_org_min;
102         twmd->map_org_max            = wmd->map_org_max;
103         twmd->map_new_min            = wmd->map_new_min;
104         twmd->map_new_max            = wmd->map_new_max;
105         twmd->cmap_curve             = curvemapping_copy(wmd->cmap_curve);
106
107         twmd->clamp_weight_min       = wmd->clamp_weight_min;
108         twmd->clamp_weight_max       = wmd->clamp_weight_max;
109
110         twmd->add_threshold          = wmd->add_threshold;
111         twmd->rem_threshold          = wmd->rem_threshold;
112
113         twmd->mask_constant          = wmd->mask_constant;
114         BLI_strncpy(twmd->mask_defgrp_name, wmd->mask_defgrp_name, sizeof(twmd->mask_defgrp_name));
115         twmd->mask_texture           = wmd->mask_texture;
116         twmd->mask_tex_use_channel   = wmd->mask_tex_use_channel;
117         twmd->mask_tex_mapping       = wmd->mask_tex_mapping;
118         twmd->mask_tex_map_obj       = wmd->mask_tex_map_obj;
119         BLI_strncpy(twmd->mask_tex_uvlayer_name, wmd->mask_tex_uvlayer_name,
120                     sizeof(twmd->mask_tex_uvlayer_name));
121 }
122
123 static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
124 {
125         WeightVGEditModifierData *wmd = (WeightVGEditModifierData*) md;
126         CustomDataMask dataMask = 0;
127
128         /* We need vertex groups! */
129         dataMask |= CD_MASK_MDEFORMVERT;
130
131         /* Ask for UV coordinates if we need them. */
132         if(wmd->mask_tex_mapping == MOD_DISP_MAP_UV)
133                 dataMask |= CD_MASK_MTFACE;
134
135         return dataMask;
136 }
137
138 static int dependsOnTime(ModifierData *md)
139 {
140         WeightVGEditModifierData *wmd = (WeightVGEditModifierData*) md;
141
142         if(wmd->mask_texture)
143                 return BKE_texture_dependsOnTime(wmd->mask_texture);
144         return 0;
145 }
146
147 static void foreachObjectLink(ModifierData *md, Object *ob,
148                               void (*walk)(void *userData, Object *ob, Object **obpoin),
149                               void *userData)
150 {
151         WeightVGEditModifierData *wmd = (WeightVGEditModifierData*) md;
152         walk(userData, ob, &wmd->mask_tex_map_obj);
153 }
154
155 static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
156 {
157         WeightVGEditModifierData *wmd = (WeightVGEditModifierData*) md;
158
159         walk(userData, ob, (ID **)&wmd->mask_texture);
160
161         foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
162 }
163
164 static void updateDepgraph(ModifierData *md, DagForest *forest, struct Scene *UNUSED(scene),
165                            Object *UNUSED(ob), DagNode *obNode)
166 {
167         WeightVGEditModifierData *wmd = (WeightVGEditModifierData*) md;
168         DagNode *curNode;
169
170         if(wmd->mask_tex_map_obj && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) {
171                 curNode = dag_get_node(forest, wmd->mask_tex_map_obj);
172
173                 dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA|DAG_RL_OB_DATA,
174                                  "WeightVGEdit Modifier");
175         }
176
177         if(wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL)
178                 dag_add_relation(forest, obNode, obNode, DAG_RL_DATA_DATA|DAG_RL_OB_DATA,
179                                  "WeightVGEdit Modifier");
180 }
181
182 static int isDisabled(ModifierData *md, int UNUSED(useRenderParams))
183 {
184         WeightVGEditModifierData *wmd = (WeightVGEditModifierData*) md;
185         /* If no vertex group, bypass. */
186         return (wmd->defgrp_name == NULL);
187 }
188
189 static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData,
190                                   int UNUSED(useRenderParams), int UNUSED(isFinalCalc))
191 {
192         WeightVGEditModifierData *wmd = (WeightVGEditModifierData*) md;
193         DerivedMesh *dm = derivedData, *ret = NULL;
194 #if 0
195         Mesh *ob_m = NULL;
196 #endif
197         MDeformVert *dvert = NULL;
198         float *org_w = NULL; /* Array original weights. */
199         float *new_w = NULL; /* Array new weights. */
200         int numVerts;
201         int defgrp_idx;
202         int i;
203         char rel_ret = 0; /* Boolean, whether we have to release ret dm or not, when not using it! */
204         float *mapf = NULL; /* Cache for mapping factors. */
205         /* Flags. */
206         char do_map   = wmd->edit_flags & MOD_WVG_EDIT_MAP;
207         char do_cmap  = wmd->edit_flags & MOD_WVG_EDIT_CMAP;
208         char do_rev   = wmd->edit_flags & MOD_WVG_EDIT_REVERSE_WEIGHTS;
209         char do_add   = wmd->edit_flags & MOD_WVG_EDIT_ADD2VG;
210         char do_rem   = wmd->edit_flags & MOD_WVG_EDIT_REMFVG;
211         char do_clamp = wmd->edit_flags & MOD_WVG_EDIT_CLAMP;
212
213         /* Get number of verts. */
214         numVerts = dm->getNumVerts(dm);
215
216         /* Check if we can just return the original mesh.
217          * Must have verts and therefore verts assigned to vgroups to do anything useful!
218          */
219         if ((numVerts == 0) || (ob->defbase.first == NULL))
220                 return dm;
221
222         /* Get vgroup idx from its name. */
223         defgrp_idx = defgroup_name_index(ob, wmd->defgrp_name);
224         if (defgrp_idx < 0)
225                 return dm;
226
227         /* XXX All this to avoid copying dm when not needed… However, it nearly doubles compute
228          *     time! See scene 5 of the WeighVG test file…
229          */
230 #if 0
231         /* Get actual dverts (ie vertex group data). */
232         dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
233         /* If no dverts, return unmodified data… */
234         if (dvert == NULL)
235                 return dm;
236
237         /* Get org mesh, only to test whether affected cdata layer has already been copied
238          * somewhere up in the modifiers stack.
239          */
240         ob_m = get_mesh(ob);
241         if (ob_m == NULL)
242                 return dm;
243
244         /* Create a copy of our dmesh, only if our affected cdata layer is the same as org mesh. */
245         if (dvert == CustomData_get_layer(&ob_m->vdata, CD_MDEFORMVERT)) {
246                 /* XXX Seems to create problems with weightpaint mode???
247                  *     I’m missing something here, I guess…
248                  */
249 //              DM_set_only_copy(dm, CD_MASK_MDEFORMVERT); /* Only copy defgroup layer. */
250                 ret = CDDM_copy(dm);
251                 dvert = ret->getVertDataArray(ret, CD_MDEFORMVERT);
252                 if (dvert == NULL) {
253                         ret->release(ret);
254                         return dm;
255                 }
256                 rel_ret = 1;
257         }
258         else
259                 ret = dm;
260 #else
261         ret = CDDM_copy(dm);
262         rel_ret = 1;
263         dvert = ret->getVertDataArray(ret, CD_MDEFORMVERT);
264         if (dvert == NULL) {
265                 if (rel_ret)
266                         ret->release(ret);
267                 return dm;
268         }
269 #endif
270
271         /* Get org weights, assuming 0.0 for vertices not in given vgroup. */
272         org_w = MEM_mallocN(sizeof(float) * numVerts, "WeightVGEdit Modifier, org_w");
273         new_w = MEM_mallocN(sizeof(float) * numVerts, "WeightVGEdit Modifier, org_w");
274         for (i = 0; i < numVerts; i++) {
275                 int j;
276                 org_w[i] = new_w[i] = wmd->default_weight;
277                 for (j = 0; j < dvert[i].totweight; j++) {
278                         if(dvert[i].dw[j].def_nr == defgrp_idx) {
279                                 org_w[i] = new_w[i] = dvert[i].dw[j].weight;
280                                 break;
281                         }
282                 }
283                 /* Do mapping. */
284                 if (do_map) {
285                         /* This mapping is a simple func: a*in + b.
286                          * with a = (out_min - out_max)/(in_min - in_max)
287                          * and  b = out_max - a*in_max
288                          * Note a and b are cached!
289                          */
290                         if (mapf == NULL) {
291                                 float denom = wmd->map_org_min - wmd->map_org_max;
292                                 mapf = MEM_mallocN(sizeof(float) * 2, "WeightVGEdit, mapf");
293                                 if (denom > 0.0 && denom < MOD_WVG_ZEROFLOOR)
294                                         denom = MOD_WVG_ZEROFLOOR;
295                                 else if (denom < 0.0 && denom > -MOD_WVG_ZEROFLOOR)
296                                         denom = -MOD_WVG_ZEROFLOOR;
297                                 mapf[0] = (wmd->map_new_min - wmd->map_new_max) / denom;
298                                 mapf[1] = wmd->map_new_max - (mapf[0] * wmd->map_org_max);
299                         }
300                         new_w[i] = (mapf[0] * new_w[i]) + mapf[1];
301                 }
302                 if (do_cmap)
303                         new_w[i] = curvemapping_evaluateF(wmd->cmap_curve, 0, new_w[i]);
304                 if (do_rev)
305                         new_w[i] = (-1.0 * new_w[i]) + 1.0;
306         }
307
308         /* Do masking. */
309         weightvg_do_mask(numVerts, NULL, org_w, new_w, ob, ret, wmd->mask_constant,
310                          wmd->mask_defgrp_name, wmd->mask_texture, wmd->mask_tex_use_channel,
311                          wmd->mask_tex_mapping, wmd->mask_tex_map_obj, wmd->mask_tex_uvlayer_name);
312
313         /* Do clamping. */
314         if (do_clamp) {
315                 for (i = 0; i < numVerts; i++)
316                         CLAMP(org_w[i], wmd->clamp_weight_min, wmd->clamp_weight_max);
317         }
318
319         /* Update/add/remove from vgroup. */
320         weightvg_update_vg(dvert, defgrp_idx, numVerts, NULL, org_w, do_add, wmd->add_threshold,
321                            do_rem, wmd->rem_threshold);
322
323         /* Freeing stuff. */
324         if (org_w)
325                 MEM_freeN(org_w);
326         if (new_w)
327                 MEM_freeN(new_w);
328         if (mapf)
329                 MEM_freeN(mapf);
330
331         /* Return the vgroup-modified mesh. */
332         return ret;
333 }
334
335 static DerivedMesh *applyModifierEM(ModifierData *md, Object *ob,
336                                     struct EditMesh *UNUSED(editData),
337                                     DerivedMesh *derivedData)
338 {
339         return applyModifier(md, ob, derivedData, 0, 1);
340 }
341
342
343 ModifierTypeInfo modifierType_WeightVGEdit = {
344         /* name */              "WeightVGEdit",
345         /* structName */        "WeightVGEditModifierData",
346         /* structSize */        sizeof(WeightVGEditModifierData),
347         /* type */              eModifierTypeType_Nonconstructive,
348         /* flags */             eModifierTypeFlag_AcceptsMesh
349 /*                             |eModifierTypeFlag_SupportsMapping*/
350                                |eModifierTypeFlag_SupportsEditmode,
351
352         /* copyData */          copyData,
353         /* deformVerts */       NULL,
354         /* deformMatrices */    NULL,
355         /* deformVertsEM */     NULL,
356         /* deformMatricesEM */  NULL,
357         /* applyModifier */     applyModifier,
358         /* applyModifierEM */   applyModifierEM,
359         /* initData */          initData,
360         /* requiredDataMask */  requiredDataMask,
361         /* freeData */          freeData,
362         /* isDisabled */        isDisabled,
363         /* updateDepgraph */    updateDepgraph,
364         /* dependsOnTime */     dependsOnTime,
365         /* dependsOnNormals */  NULL,
366         /* foreachObjectLink */ foreachObjectLink,
367         /* foreachIDLink */     foreachIDLink,
368 };
369