svn merge -r40197:40311 ^/trunk/blender
[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             = 0;
65         wmd->falloff_type           = MOD_WVG_MAPPING_NONE;
66         wmd->default_weight         = 0.0f;
67
68         wmd->cmap_curve             = curvemapping_add(1, 0.0, 0.0, 1.0, 1.0);
69         curvemapping_initialize(wmd->cmap_curve);
70
71         wmd->rem_threshold          = 0.01f;
72         wmd->add_threshold          = 0.01f;
73
74         wmd->mask_constant          = 1.0f;
75         wmd->mask_tex_use_channel   = MOD_WVG_MASK_TEX_USE_INT; /* Use intensity by default. */
76         wmd->mask_tex_mapping       = MOD_DISP_MAP_LOCAL;
77 }
78
79 static void freeData(ModifierData *md)
80 {
81         WeightVGEditModifierData *wmd = (WeightVGEditModifierData*) md;
82         curvemapping_free(wmd->cmap_curve);
83 }
84
85 static void copyData(ModifierData *md, ModifierData *target)
86 {
87         WeightVGEditModifierData *wmd  = (WeightVGEditModifierData*) md;
88         WeightVGEditModifierData *twmd = (WeightVGEditModifierData*) target;
89
90         BLI_strncpy(twmd->defgrp_name, wmd->defgrp_name, sizeof(twmd->defgrp_name));
91
92         twmd->edit_flags             = wmd->edit_flags;
93         twmd->falloff_type           = wmd->falloff_type;
94         twmd->default_weight         = wmd->default_weight;
95
96         twmd->cmap_curve             = curvemapping_copy(wmd->cmap_curve);
97
98         twmd->add_threshold          = wmd->add_threshold;
99         twmd->rem_threshold          = wmd->rem_threshold;
100
101         twmd->mask_constant          = wmd->mask_constant;
102         BLI_strncpy(twmd->mask_defgrp_name, wmd->mask_defgrp_name, sizeof(twmd->mask_defgrp_name));
103         twmd->mask_texture           = wmd->mask_texture;
104         twmd->mask_tex_use_channel   = wmd->mask_tex_use_channel;
105         twmd->mask_tex_mapping       = wmd->mask_tex_mapping;
106         twmd->mask_tex_map_obj       = wmd->mask_tex_map_obj;
107         BLI_strncpy(twmd->mask_tex_uvlayer_name, wmd->mask_tex_uvlayer_name, sizeof(twmd->mask_tex_uvlayer_name));
108 }
109
110 static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
111 {
112         WeightVGEditModifierData *wmd = (WeightVGEditModifierData*) md;
113         CustomDataMask dataMask = 0;
114
115         /* We need vertex groups! */
116         dataMask |= CD_MASK_MDEFORMVERT;
117
118         /* Ask for UV coordinates if we need them. */
119         if(wmd->mask_tex_mapping == MOD_DISP_MAP_UV)
120                 dataMask |= CD_MASK_MTFACE;
121
122         return dataMask;
123 }
124
125 static int dependsOnTime(ModifierData *md)
126 {
127         WeightVGEditModifierData *wmd = (WeightVGEditModifierData*) md;
128
129         if(wmd->mask_texture)
130                 return BKE_texture_dependsOnTime(wmd->mask_texture);
131         return 0;
132 }
133
134 static void foreachObjectLink(ModifierData *md, Object *ob,
135                               void (*walk)(void *userData, Object *ob, Object **obpoin),
136                               void *userData)
137 {
138         WeightVGEditModifierData *wmd = (WeightVGEditModifierData*) md;
139         walk(userData, ob, &wmd->mask_tex_map_obj);
140 }
141
142 static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
143 {
144         WeightVGEditModifierData *wmd = (WeightVGEditModifierData*) md;
145
146         walk(userData, ob, (ID **)&wmd->mask_texture);
147
148         foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
149 }
150
151 static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void *userData)
152 {
153         walk(userData, ob, md, "mask_texture");
154 }
155
156 static void updateDepgraph(ModifierData *md, DagForest *forest, struct Scene *UNUSED(scene),
157                            Object *UNUSED(ob), DagNode *obNode)
158 {
159         WeightVGEditModifierData *wmd = (WeightVGEditModifierData*) md;
160         DagNode *curNode;
161
162         if(wmd->mask_tex_map_obj && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) {
163                 curNode = dag_get_node(forest, wmd->mask_tex_map_obj);
164
165                 dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA|DAG_RL_OB_DATA,
166                                  "WeightVGEdit Modifier");
167         }
168
169         if(wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL)
170                 dag_add_relation(forest, obNode, obNode, DAG_RL_DATA_DATA|DAG_RL_OB_DATA,
171                                  "WeightVGEdit Modifier");
172 }
173
174 static int isDisabled(ModifierData *md, int UNUSED(useRenderParams))
175 {
176         WeightVGEditModifierData *wmd = (WeightVGEditModifierData*) md;
177         /* If no vertex group, bypass. */
178         return (wmd->defgrp_name[0] == '\0');
179 }
180
181 static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData,
182                                   int UNUSED(useRenderParams), int UNUSED(isFinalCalc))
183 {
184         WeightVGEditModifierData *wmd = (WeightVGEditModifierData*) md;
185         DerivedMesh *dm = derivedData, *ret = NULL;
186 #if 0
187         Mesh *ob_m = NULL;
188 #endif
189         MDeformVert *dvert = NULL;
190         MDeformWeight **dw = NULL;
191         float *org_w; /* Array original weights. */
192         float *new_w; /* Array new weights. */
193         int numVerts;
194         int defgrp_idx;
195         int i;
196         char rel_ret = 0; /* Boolean, whether we have to release ret dm or not, when not using it! */
197         /* Flags. */
198         int do_add = (wmd->edit_flags & MOD_WVG_EDIT_ADD2VG) != 0;
199         int do_rem = (wmd->edit_flags & MOD_WVG_EDIT_REMFVG) != 0;
200
201         /* Get number of verts. */
202         numVerts = dm->getNumVerts(dm);
203
204         /* Check if we can just return the original mesh.
205          * Must have verts and therefore verts assigned to vgroups to do anything useful!
206          */
207         if ((numVerts == 0) || (ob->defbase.first == NULL))
208                 return dm;
209
210         /* Get vgroup idx from its name. */
211         defgrp_idx = defgroup_name_index(ob, wmd->defgrp_name);
212         if (defgrp_idx < 0)
213                 return dm;
214
215         /* XXX All this to avoid copying dm when not needed... However, it nearly doubles compute
216          *     time! See scene 5 of the WeighVG test file...
217          */
218 #if 0
219         /* Get actual dverts (ie vertex group data). */
220         dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
221         /* If no dverts, return unmodified data... */
222         if (dvert == NULL)
223                 return dm;
224
225         /* Get org mesh, only to test whether affected cdata layer has already been copied
226          * somewhere up in the modifiers stack.
227          */
228         ob_m = get_mesh(ob);
229         if (ob_m == NULL)
230                 return dm;
231
232         /* Create a copy of our dmesh, only if our affected cdata layer is the same as org mesh. */
233         if (dvert == CustomData_get_layer(&ob_m->vdata, CD_MDEFORMVERT)) {
234                 /* XXX Seems to create problems with weightpaint mode???
235                  *     I'm missing something here, I guess...
236                  */
237 //              DM_set_only_copy(dm, CD_MASK_MDEFORMVERT); /* Only copy defgroup layer. */
238                 ret = CDDM_copy(dm);
239                 dvert = ret->getVertDataArray(ret, CD_MDEFORMVERT);
240                 if (dvert == NULL) {
241                         ret->release(ret);
242                         return dm;
243                 }
244                 rel_ret = 1;
245         }
246         else
247                 ret = dm;
248 #else
249         ret = CDDM_copy(dm);
250         rel_ret = 1;
251         dvert = ret->getVertDataArray(ret, CD_MDEFORMVERT);
252         if (dvert == NULL) {
253                 if (rel_ret)
254                         ret->release(ret);
255                 return dm;
256         }
257 #endif
258
259         /* Get org weights, assuming 0.0 for vertices not in given vgroup. */
260         org_w = MEM_mallocN(sizeof(float) * numVerts, "WeightVGEdit Modifier, org_w");
261         new_w = MEM_mallocN(sizeof(float) * numVerts, "WeightVGEdit Modifier, new_w");
262         dw = MEM_mallocN(sizeof(MDeformWeight*) * numVerts, "WeightVGEdit Modifier, dw");
263         for (i = 0; i < numVerts; i++) {
264                 dw[i] = defvert_find_index(&dvert[i], defgrp_idx);
265                 if(dw[i]) {
266                         org_w[i] = new_w[i] = dw[i]->weight;
267                 }
268                 else {
269                         org_w[i] = new_w[i] = wmd->default_weight;
270                 }
271         }
272
273         /* Do mapping. */
274         if (wmd->falloff_type != MOD_WVG_MAPPING_NONE) {
275                 weightvg_do_map(numVerts, new_w, wmd->falloff_type, wmd->cmap_curve);
276         }
277
278         /* Do masking. */
279         weightvg_do_mask(numVerts, NULL, org_w, new_w, ob, ret, wmd->mask_constant,
280                          wmd->mask_defgrp_name, wmd->mask_texture, wmd->mask_tex_use_channel,
281                          wmd->mask_tex_mapping, wmd->mask_tex_map_obj, wmd->mask_tex_uvlayer_name);
282
283         /* Update/add/remove from vgroup. */
284         weightvg_update_vg(dvert, defgrp_idx, dw, numVerts, NULL, org_w, do_add, wmd->add_threshold,
285                            do_rem, wmd->rem_threshold);
286
287         /* Freeing stuff. */
288         MEM_freeN(org_w);
289         MEM_freeN(new_w);
290         MEM_freeN(dw);
291
292         /* Return the vgroup-modified mesh. */
293         return ret;
294 }
295
296 static DerivedMesh *applyModifierEM(ModifierData *md, Object *ob,
297                                     struct EditMesh *UNUSED(editData),
298                                     DerivedMesh *derivedData)
299 {
300         return applyModifier(md, ob, derivedData, 0, 1);
301 }
302
303
304 ModifierTypeInfo modifierType_WeightVGEdit = {
305         /* name */              "VertexWeightEdit",
306         /* structName */        "WeightVGEditModifierData",
307         /* structSize */        sizeof(WeightVGEditModifierData),
308         /* type */              eModifierTypeType_Nonconstructive,
309         /* flags */             eModifierTypeFlag_AcceptsMesh
310 /*                             |eModifierTypeFlag_SupportsMapping*/
311                                |eModifierTypeFlag_SupportsEditmode,
312
313         /* copyData */          copyData,
314         /* deformVerts */       NULL,
315         /* deformMatrices */    NULL,
316         /* deformVertsEM */     NULL,
317         /* deformMatricesEM */  NULL,
318         /* applyModifier */     applyModifier,
319         /* applyModifierEM */   applyModifierEM,
320         /* initData */          initData,
321         /* requiredDataMask */  requiredDataMask,
322         /* freeData */          freeData,
323         /* isDisabled */        isDisabled,
324         /* updateDepgraph */    updateDepgraph,
325         /* dependsOnTime */     dependsOnTime,
326         /* dependsOnNormals */  NULL,
327         /* foreachObjectLink */ foreachObjectLink,
328         /* foreachIDLink */     foreachIDLink,
329         /* foreachTexLink */    foreachTexLink,
330 };