Cleanup: extra semicolon, comma warnings
[blender.git] / source / blender / modifiers / intern / MOD_weightvgmix.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software  Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2011 by Bastien Montagne.
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup modifiers
22  */
23
24 #include "BLI_utildefines.h"
25
26 #include "BLI_listbase.h"
27 #include "BLI_math.h"
28
29 #include "DNA_mesh_types.h"
30 #include "DNA_meshdata_types.h"
31 #include "DNA_modifier_types.h"
32 #include "DNA_object_types.h"
33
34 #include "BKE_customdata.h"
35 #include "BKE_deform.h"
36 #include "BKE_library_query.h"
37 #include "BKE_modifier.h"
38 #include "BKE_texture.h" /* Texture masking. */
39
40 #include "DEG_depsgraph_build.h"
41 #include "DEG_depsgraph_query.h"
42
43 #include "MEM_guardedalloc.h"
44
45 #include "MOD_weightvg_util.h"
46 #include "MOD_modifiertypes.h"
47
48 /**
49  * This mixes the old weight with the new weight factor.
50  */
51 static float mix_weight(float weight, float weight2, char mix_mode)
52 {
53 #if 0
54   /*
55    * XXX Don't know why, but the switch version takes many CPU time,
56    *     and produces lag in realtime playback...
57    */
58   switch (mix_mode) {
59     case MOD_WVG_MIX_ADD:
60       return (weight + weight2);
61     case MOD_WVG_MIX_SUB:
62       return (weight - weight2);
63     case MOD_WVG_MIX_MUL:
64       return (weight * weight2);
65     case MOD_WVG_MIX_DIV:
66       /* Avoid dividing by zero (or really small values). */
67       if (0.0 <= weight2 < MOD_WVG_ZEROFLOOR) {
68         weight2 = MOD_WVG_ZEROFLOOR;
69       }
70       else if (-MOD_WVG_ZEROFLOOR < weight2) {
71         weight2 = -MOD_WVG_ZEROFLOOR;
72       }
73       return (weight / weight2);
74     case MOD_WVG_MIX_DIF:
75       return (weight < weight2 ? weight2 - weight : weight - weight2);
76     case MOD_WVG_MIX_AVG:
77       return (weight + weight2) / 2.0;
78     case MOD_WVG_MIX_SET:
79     default:
80       return weight2;
81   }
82 #endif
83   if (mix_mode == MOD_WVG_MIX_SET) {
84     return weight2;
85   }
86   else if (mix_mode == MOD_WVG_MIX_ADD) {
87     return (weight + weight2);
88   }
89   else if (mix_mode == MOD_WVG_MIX_SUB) {
90     return (weight - weight2);
91   }
92   else if (mix_mode == MOD_WVG_MIX_MUL) {
93     return (weight * weight2);
94   }
95   else if (mix_mode == MOD_WVG_MIX_DIV) {
96     /* Avoid dividing by zero (or really small values). */
97     if (weight2 < 0.0f && weight2 > -MOD_WVG_ZEROFLOOR) {
98       weight2 = -MOD_WVG_ZEROFLOOR;
99     }
100     else if (weight2 >= 0.0f && weight2 < MOD_WVG_ZEROFLOOR) {
101       weight2 = MOD_WVG_ZEROFLOOR;
102     }
103     return (weight / weight2);
104   }
105   else if (mix_mode == MOD_WVG_MIX_DIF) {
106     return (weight < weight2 ? weight2 - weight : weight - weight2);
107   }
108   else if (mix_mode == MOD_WVG_MIX_AVG) {
109     return (weight + weight2) * 0.5f;
110   }
111   else {
112     return weight2;
113   }
114 }
115
116 /**************************************
117  * Modifiers functions.               *
118  **************************************/
119 static void initData(ModifierData *md)
120 {
121   WeightVGMixModifierData *wmd = (WeightVGMixModifierData *)md;
122
123   wmd->default_weight_a = 0.0f;
124   wmd->default_weight_b = 0.0f;
125   wmd->mix_mode = MOD_WVG_MIX_SET;
126   wmd->mix_set = MOD_WVG_SET_AND;
127
128   wmd->mask_constant = 1.0f;
129   wmd->mask_tex_use_channel = MOD_WVG_MASK_TEX_USE_INT; /* Use intensity by default. */
130   wmd->mask_tex_mapping = MOD_DISP_MAP_LOCAL;
131 }
132
133 static void requiredDataMask(Object *UNUSED(ob),
134                              ModifierData *md,
135                              CustomData_MeshMasks *r_cddata_masks)
136 {
137   WeightVGMixModifierData *wmd = (WeightVGMixModifierData *)md;
138
139   /* We need vertex groups! */
140   r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
141
142   /* Ask for UV coordinates if we need them. */
143   if (wmd->mask_tex_mapping == MOD_DISP_MAP_UV) {
144     r_cddata_masks->fmask |= CD_MASK_MTFACE;
145   }
146
147   /* No need to ask for CD_PREVIEW_MLOOPCOL... */
148 }
149
150 static bool dependsOnTime(ModifierData *md)
151 {
152   WeightVGMixModifierData *wmd = (WeightVGMixModifierData *)md;
153
154   if (wmd->mask_texture) {
155     return BKE_texture_dependsOnTime(wmd->mask_texture);
156   }
157   return false;
158 }
159
160 static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData)
161 {
162   WeightVGMixModifierData *wmd = (WeightVGMixModifierData *)md;
163   walk(userData, ob, &wmd->mask_tex_map_obj, IDWALK_CB_NOP);
164 }
165
166 static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
167 {
168   WeightVGMixModifierData *wmd = (WeightVGMixModifierData *)md;
169
170   walk(userData, ob, (ID **)&wmd->mask_texture, IDWALK_CB_USER);
171
172   foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
173 }
174
175 static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void *userData)
176 {
177   walk(userData, ob, md, "mask_texture");
178 }
179
180 static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
181 {
182   WeightVGMixModifierData *wmd = (WeightVGMixModifierData *)md;
183   if (wmd->mask_tex_map_obj != NULL && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) {
184     DEG_add_object_relation(
185         ctx->node, wmd->mask_tex_map_obj, DEG_OB_COMP_TRANSFORM, "WeightVGMix Modifier");
186     DEG_add_object_relation(
187         ctx->node, wmd->mask_tex_map_obj, DEG_OB_COMP_GEOMETRY, "WeightVGMix Modifier");
188
189     DEG_add_modifier_to_transform_relation(ctx->node, "WeightVGMix Modifier");
190   }
191   else if (wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL) {
192     DEG_add_modifier_to_transform_relation(ctx->node, "WeightVGMix Modifier");
193   }
194   if (wmd->mask_texture != NULL) {
195     DEG_add_generic_id_relation(ctx->node, &wmd->mask_texture->id, "WeightVGMix Modifier");
196   }
197 }
198
199 static bool isDisabled(const struct Scene *UNUSED(scene),
200                        ModifierData *md,
201                        bool UNUSED(useRenderParams))
202 {
203   WeightVGMixModifierData *wmd = (WeightVGMixModifierData *)md;
204   /* If no vertex group, bypass. */
205   return (wmd->defgrp_name_a[0] == '\0');
206 }
207
208 static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
209 {
210   BLI_assert(mesh != NULL);
211
212   WeightVGMixModifierData *wmd = (WeightVGMixModifierData *)md;
213
214   MDeformVert *dvert = NULL;
215   MDeformWeight **dw1, **tdw1, **dw2, **tdw2;
216   float *org_w;
217   float *new_w;
218   int *tidx, *indices = NULL;
219   int numIdx = 0;
220   int i;
221   /* Flags. */
222 #if 0
223   const bool do_prev = (wmd->modifier.mode & eModifierMode_DoWeightPreview) != 0;
224 #endif
225
226   /* Get number of verts. */
227   const int numVerts = mesh->totvert;
228
229   /* Check if we can just return the original mesh.
230    * Must have verts and therefore verts assigned to vgroups to do anything useful!
231    */
232   if ((numVerts == 0) || BLI_listbase_is_empty(&ctx->object->defbase)) {
233     return mesh;
234   }
235
236   /* Get vgroup idx from its name. */
237   const int defgrp_index = defgroup_name_index(ctx->object, wmd->defgrp_name_a);
238   if (defgrp_index == -1) {
239     return mesh;
240   }
241   /* Get second vgroup idx from its name, if given. */
242   int defgrp_index_other = -1;
243   if (wmd->defgrp_name_b[0] != '\0') {
244     defgrp_index_other = defgroup_name_index(ctx->object, wmd->defgrp_name_b);
245     if (defgrp_index_other == -1) {
246       return mesh;
247     }
248   }
249
250   const bool has_mdef = CustomData_has_layer(&mesh->vdata, CD_MDEFORMVERT);
251   /* If no vertices were ever added to an object's vgroup, dvert might be NULL. */
252   if (!has_mdef) {
253     /* If not affecting all vertices, just return. */
254     if (wmd->mix_set != MOD_WVG_SET_ALL) {
255       return mesh;
256     }
257   }
258
259   if (has_mdef) {
260     dvert = CustomData_duplicate_referenced_layer(&mesh->vdata, CD_MDEFORMVERT, numVerts);
261   }
262   else {
263     /* Add a valid data layer! */
264     dvert = CustomData_add_layer(&mesh->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, numVerts);
265   }
266   /* Ultimate security check. */
267   if (!dvert) {
268     return mesh;
269   }
270   mesh->dvert = dvert;
271
272   /* Find out which vertices to work on. */
273   tidx = MEM_malloc_arrayN(numVerts, sizeof(int), "WeightVGMix Modifier, tidx");
274   tdw1 = MEM_malloc_arrayN(numVerts, sizeof(MDeformWeight *), "WeightVGMix Modifier, tdw1");
275   tdw2 = MEM_malloc_arrayN(numVerts, sizeof(MDeformWeight *), "WeightVGMix Modifier, tdw2");
276   switch (wmd->mix_set) {
277     case MOD_WVG_SET_A:
278       /* All vertices in first vgroup. */
279       for (i = 0; i < numVerts; i++) {
280         MDeformWeight *dw = defvert_find_index(&dvert[i], defgrp_index);
281         if (dw) {
282           tdw1[numIdx] = dw;
283           tdw2[numIdx] = (defgrp_index_other >= 0) ?
284                              defvert_find_index(&dvert[i], defgrp_index_other) :
285                              NULL;
286           tidx[numIdx++] = i;
287         }
288       }
289       break;
290     case MOD_WVG_SET_B:
291       /* All vertices in second vgroup. */
292       for (i = 0; i < numVerts; i++) {
293         MDeformWeight *dw = (defgrp_index_other >= 0) ?
294                                 defvert_find_index(&dvert[i], defgrp_index_other) :
295                                 NULL;
296         if (dw) {
297           tdw1[numIdx] = defvert_find_index(&dvert[i], defgrp_index);
298           tdw2[numIdx] = dw;
299           tidx[numIdx++] = i;
300         }
301       }
302       break;
303     case MOD_WVG_SET_OR:
304       /* All vertices in one vgroup or the other. */
305       for (i = 0; i < numVerts; i++) {
306         MDeformWeight *adw = defvert_find_index(&dvert[i], defgrp_index);
307         MDeformWeight *bdw = (defgrp_index_other >= 0) ?
308                                  defvert_find_index(&dvert[i], defgrp_index_other) :
309                                  NULL;
310         if (adw || bdw) {
311           tdw1[numIdx] = adw;
312           tdw2[numIdx] = bdw;
313           tidx[numIdx++] = i;
314         }
315       }
316       break;
317     case MOD_WVG_SET_AND:
318       /* All vertices in both vgroups. */
319       for (i = 0; i < numVerts; i++) {
320         MDeformWeight *adw = defvert_find_index(&dvert[i], defgrp_index);
321         MDeformWeight *bdw = (defgrp_index_other >= 0) ?
322                                  defvert_find_index(&dvert[i], defgrp_index_other) :
323                                  NULL;
324         if (adw && bdw) {
325           tdw1[numIdx] = adw;
326           tdw2[numIdx] = bdw;
327           tidx[numIdx++] = i;
328         }
329       }
330       break;
331     case MOD_WVG_SET_ALL:
332     default:
333       /* Use all vertices. */
334       for (i = 0; i < numVerts; i++) {
335         tdw1[i] = defvert_find_index(&dvert[i], defgrp_index);
336         tdw2[i] = (defgrp_index_other >= 0) ? defvert_find_index(&dvert[i], defgrp_index_other) :
337                                               NULL;
338       }
339       numIdx = -1;
340       break;
341   }
342   if (numIdx == 0) {
343     /* Use no vertices! Hence, return org data. */
344     MEM_freeN(tdw1);
345     MEM_freeN(tdw2);
346     MEM_freeN(tidx);
347     return mesh;
348   }
349   if (numIdx != -1) {
350     indices = MEM_malloc_arrayN(numIdx, sizeof(int), "WeightVGMix Modifier, indices");
351     memcpy(indices, tidx, sizeof(int) * numIdx);
352     dw1 = MEM_malloc_arrayN(numIdx, sizeof(MDeformWeight *), "WeightVGMix Modifier, dw1");
353     memcpy(dw1, tdw1, sizeof(MDeformWeight *) * numIdx);
354     MEM_freeN(tdw1);
355     dw2 = MEM_malloc_arrayN(numIdx, sizeof(MDeformWeight *), "WeightVGMix Modifier, dw2");
356     memcpy(dw2, tdw2, sizeof(MDeformWeight *) * numIdx);
357     MEM_freeN(tdw2);
358   }
359   else {
360     /* Use all vertices. */
361     numIdx = numVerts;
362     /* Just copy MDeformWeight pointers arrays, they will be freed at the end. */
363     dw1 = tdw1;
364     dw2 = tdw2;
365   }
366   MEM_freeN(tidx);
367
368   org_w = MEM_malloc_arrayN(numIdx, sizeof(float), "WeightVGMix Modifier, org_w");
369   new_w = MEM_malloc_arrayN(numIdx, sizeof(float), "WeightVGMix Modifier, new_w");
370
371   /* Mix weights. */
372   for (i = 0; i < numIdx; i++) {
373     float weight2;
374     org_w[i] = dw1[i] ? dw1[i]->weight : wmd->default_weight_a;
375     weight2 = dw2[i] ? dw2[i]->weight : wmd->default_weight_b;
376
377     new_w[i] = mix_weight(org_w[i], weight2, wmd->mix_mode);
378   }
379
380   /* Do masking. */
381   struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
382   weightvg_do_mask(ctx,
383                    numIdx,
384                    indices,
385                    org_w,
386                    new_w,
387                    ctx->object,
388                    mesh,
389                    wmd->mask_constant,
390                    wmd->mask_defgrp_name,
391                    scene,
392                    wmd->mask_texture,
393                    wmd->mask_tex_use_channel,
394                    wmd->mask_tex_mapping,
395                    wmd->mask_tex_map_obj,
396                    wmd->mask_tex_uvlayer_name);
397
398   /* Update (add to) vgroup.
399    * XXX Depending on the MOD_WVG_SET_xxx option chosen, we might have to add vertices to vgroup.
400    */
401   weightvg_update_vg(
402       dvert, defgrp_index, dw1, numIdx, indices, org_w, true, -FLT_MAX, false, 0.0f);
403
404   /* If weight preview enabled... */
405 #if 0 /* XXX Currently done in mod stack :/ */
406   if (do_prev) {
407     DM_update_weight_mcol(ob, dm, 0, org_w, numIdx, indices);
408   }
409 #endif
410
411   /* Freeing stuff. */
412   MEM_freeN(org_w);
413   MEM_freeN(new_w);
414   MEM_freeN(dw1);
415   MEM_freeN(dw2);
416   MEM_SAFE_FREE(indices);
417
418   /* Return the vgroup-modified mesh. */
419   return mesh;
420 }
421
422 ModifierTypeInfo modifierType_WeightVGMix = {
423     /* name */ "VertexWeightMix",
424     /* structName */ "WeightVGMixModifierData",
425     /* structSize */ sizeof(WeightVGMixModifierData),
426     /* type */ eModifierTypeType_NonGeometrical,
427     /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping |
428         eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_UsesPreview,
429
430     /* copyData */ modifier_copyData_generic,
431
432     /* deformVerts */ NULL,
433     /* deformMatrices */ NULL,
434     /* deformVertsEM */ NULL,
435     /* deformMatricesEM */ NULL,
436     /* applyModifier */ applyModifier,
437
438     /* initData */ initData,
439     /* requiredDataMask */ requiredDataMask,
440     /* freeData */ NULL,
441     /* isDisabled */ isDisabled,
442     /* updateDepsgraph */ updateDepsgraph,
443     /* dependsOnTime */ dependsOnTime,
444     /* dependsOnNormals */ NULL,
445     /* foreachObjectLink */ foreachObjectLink,
446     /* foreachIDLink */ foreachIDLink,
447     /* foreachTexLink */ foreachTexLink,
448     /* freeRuntimeData */ NULL,
449 };