Cleanup: warning on windows
[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 "BLT_translation.h"
30
31 #include "DNA_defaults.h"
32 #include "DNA_mesh_types.h"
33 #include "DNA_meshdata_types.h"
34 #include "DNA_modifier_types.h"
35 #include "DNA_object_types.h"
36 #include "DNA_screen_types.h"
37
38 #include "BKE_context.h"
39 #include "BKE_customdata.h"
40 #include "BKE_deform.h"
41 #include "BKE_lib_query.h"
42 #include "BKE_modifier.h"
43 #include "BKE_screen.h"
44 #include "BKE_texture.h" /* Texture masking. */
45
46 #include "UI_interface.h"
47 #include "UI_resources.h"
48
49 #include "RNA_access.h"
50
51 #include "DEG_depsgraph_build.h"
52 #include "DEG_depsgraph_query.h"
53
54 #include "MEM_guardedalloc.h"
55
56 #include "MOD_modifiertypes.h"
57 #include "MOD_ui_common.h"
58 #include "MOD_util.h"
59 #include "MOD_weightvg_util.h"
60
61 /**
62  * This mixes the old weight with the new weight factor.
63  */
64 static float mix_weight(float weight, float weight2, char mix_mode)
65 {
66 #if 0
67   /*
68    * XXX Don't know why, but the switch version takes many CPU time,
69    *     and produces lag in realtime playback...
70    */
71   switch (mix_mode) {
72     case MOD_WVG_MIX_ADD:
73       return (weight + weight2);
74     case MOD_WVG_MIX_SUB:
75       return (weight - weight2);
76     case MOD_WVG_MIX_MUL:
77       return (weight * weight2);
78     case MOD_WVG_MIX_DIV:
79       /* Avoid dividing by zero (or really small values). */
80       if (0.0 <= weight2 < MOD_WVG_ZEROFLOOR) {
81         weight2 = MOD_WVG_ZEROFLOOR;
82       }
83       else if (-MOD_WVG_ZEROFLOOR < weight2) {
84         weight2 = -MOD_WVG_ZEROFLOOR;
85       }
86       return (weight / weight2);
87     case MOD_WVG_MIX_DIF:
88       return (weight < weight2 ? weight2 - weight : weight - weight2);
89     case MOD_WVG_MIX_AVG:
90       return (weight + weight2) / 2.0;
91     case MOD_WVG_MIX_SET:
92     default:
93       return weight2;
94   }
95 #endif
96   if (mix_mode == MOD_WVG_MIX_SET) {
97     return weight2;
98   }
99   if (mix_mode == MOD_WVG_MIX_ADD) {
100     return (weight + weight2);
101   }
102   if (mix_mode == MOD_WVG_MIX_SUB) {
103     return (weight - weight2);
104   }
105   if (mix_mode == MOD_WVG_MIX_MUL) {
106     return (weight * weight2);
107   }
108   if (mix_mode == MOD_WVG_MIX_DIV) {
109     /* Avoid dividing by zero (or really small values). */
110     if (weight2 < 0.0f && weight2 > -MOD_WVG_ZEROFLOOR) {
111       weight2 = -MOD_WVG_ZEROFLOOR;
112     }
113     else if (weight2 >= 0.0f && weight2 < MOD_WVG_ZEROFLOOR) {
114       weight2 = MOD_WVG_ZEROFLOOR;
115     }
116     return (weight / weight2);
117   }
118   if (mix_mode == MOD_WVG_MIX_DIF) {
119     return (weight < weight2 ? weight2 - weight : weight - weight2);
120   }
121   if (mix_mode == MOD_WVG_MIX_AVG) {
122     return (weight + weight2) * 0.5f;
123   }
124
125   return weight2;
126 }
127
128 /**************************************
129  * Modifiers functions.               *
130  **************************************/
131 static void initData(ModifierData *md)
132 {
133   WeightVGMixModifierData *wmd = (WeightVGMixModifierData *)md;
134
135   BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(wmd, modifier));
136
137   MEMCPY_STRUCT_AFTER(wmd, DNA_struct_default_get(WeightVGMixModifierData), modifier);
138 }
139
140 static void requiredDataMask(Object *UNUSED(ob),
141                              ModifierData *md,
142                              CustomData_MeshMasks *r_cddata_masks)
143 {
144   WeightVGMixModifierData *wmd = (WeightVGMixModifierData *)md;
145
146   /* We need vertex groups! */
147   r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
148
149   /* Ask for UV coordinates if we need them. */
150   if (wmd->mask_tex_mapping == MOD_DISP_MAP_UV) {
151     r_cddata_masks->fmask |= CD_MASK_MTFACE;
152   }
153
154   /* No need to ask for CD_PREVIEW_MLOOPCOL... */
155 }
156
157 static bool dependsOnTime(ModifierData *md)
158 {
159   WeightVGMixModifierData *wmd = (WeightVGMixModifierData *)md;
160
161   if (wmd->mask_texture) {
162     return BKE_texture_dependsOnTime(wmd->mask_texture);
163   }
164   return false;
165 }
166
167 static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
168 {
169   WeightVGMixModifierData *wmd = (WeightVGMixModifierData *)md;
170
171   walk(userData, ob, (ID **)&wmd->mask_texture, IDWALK_CB_USER);
172   walk(userData, ob, (ID **)&wmd->mask_tex_map_obj, IDWALK_CB_NOP);
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   bool need_transform_relation = false;
184
185   if (wmd->mask_texture != NULL) {
186     DEG_add_generic_id_relation(ctx->node, &wmd->mask_texture->id, "WeightVGMix Modifier");
187
188     if (wmd->mask_tex_map_obj != NULL && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) {
189       MOD_depsgraph_update_object_bone_relation(
190           ctx->node, wmd->mask_tex_map_obj, wmd->mask_tex_map_bone, "WeightVGMix Modifier");
191       need_transform_relation = true;
192     }
193     else if (wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL) {
194       need_transform_relation = true;
195     }
196   }
197
198   if (need_transform_relation) {
199     DEG_add_modifier_to_transform_relation(ctx->node, "WeightVGMix Modifier");
200   }
201 }
202
203 static bool isDisabled(const struct Scene *UNUSED(scene),
204                        ModifierData *md,
205                        bool UNUSED(useRenderParams))
206 {
207   WeightVGMixModifierData *wmd = (WeightVGMixModifierData *)md;
208   /* If no vertex group, bypass. */
209   return (wmd->defgrp_name_a[0] == '\0');
210 }
211
212 static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
213 {
214   BLI_assert(mesh != NULL);
215
216   WeightVGMixModifierData *wmd = (WeightVGMixModifierData *)md;
217
218   MDeformVert *dvert = NULL;
219   MDeformWeight **dw1, **tdw1, **dw2, **tdw2;
220   float *org_w;
221   float *new_w;
222   int *tidx, *indices = NULL;
223   int numIdx = 0;
224   int i;
225   const bool invert_vgroup_mask = (wmd->flag & MOD_WVG_MIX_INVERT_VGROUP_MASK) != 0;
226   const bool do_normalize = (wmd->flag & MOD_WVG_MIX_WEIGHTS_NORMALIZE) != 0;
227
228   /*
229    * Note that we only invert the weight values within provided vgroups, the selection based on
230    * which vertice is affected because it belongs or not to a group remains unchanged.
231    * In other words, vertices not belonging to a group won't be affected, even though their
232    * inverted 'virtual' weight would be 1.0f.
233    */
234   const bool invert_vgroup_a = (wmd->flag & MOD_WVG_MIX_INVERT_VGROUP_A) != 0;
235   const bool invert_vgroup_b = (wmd->flag & MOD_WVG_MIX_INVERT_VGROUP_B) != 0;
236
237   /* Flags. */
238 #if 0
239   const bool do_prev = (wmd->modifier.mode & eModifierMode_DoWeightPreview) != 0;
240 #endif
241
242   /* Get number of verts. */
243   const int numVerts = mesh->totvert;
244
245   /* Check if we can just return the original mesh.
246    * Must have verts and therefore verts assigned to vgroups to do anything useful!
247    */
248   if ((numVerts == 0) || BLI_listbase_is_empty(&ctx->object->defbase)) {
249     return mesh;
250   }
251
252   /* Get vgroup idx from its name. */
253   const int defgrp_index = BKE_object_defgroup_name_index(ctx->object, wmd->defgrp_name_a);
254   if (defgrp_index == -1) {
255     return mesh;
256   }
257   /* Get second vgroup idx from its name, if given. */
258   int defgrp_index_other = -1;
259   if (wmd->defgrp_name_b[0] != '\0') {
260     defgrp_index_other = BKE_object_defgroup_name_index(ctx->object, wmd->defgrp_name_b);
261     if (defgrp_index_other == -1) {
262       return mesh;
263     }
264   }
265
266   const bool has_mdef = CustomData_has_layer(&mesh->vdata, CD_MDEFORMVERT);
267   /* If no vertices were ever added to an object's vgroup, dvert might be NULL. */
268   if (!has_mdef) {
269     /* If not affecting all vertices, just return. */
270     if (wmd->mix_set != MOD_WVG_SET_ALL) {
271       return mesh;
272     }
273   }
274
275   if (has_mdef) {
276     dvert = CustomData_duplicate_referenced_layer(&mesh->vdata, CD_MDEFORMVERT, numVerts);
277   }
278   else {
279     /* Add a valid data layer! */
280     dvert = CustomData_add_layer(&mesh->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, numVerts);
281   }
282   /* Ultimate security check. */
283   if (!dvert) {
284     return mesh;
285   }
286   mesh->dvert = dvert;
287
288   /* Find out which vertices to work on. */
289   tidx = MEM_malloc_arrayN(numVerts, sizeof(int), "WeightVGMix Modifier, tidx");
290   tdw1 = MEM_malloc_arrayN(numVerts, sizeof(MDeformWeight *), "WeightVGMix Modifier, tdw1");
291   tdw2 = MEM_malloc_arrayN(numVerts, sizeof(MDeformWeight *), "WeightVGMix Modifier, tdw2");
292   switch (wmd->mix_set) {
293     case MOD_WVG_SET_A:
294       /* All vertices in first vgroup. */
295       for (i = 0; i < numVerts; i++) {
296         MDeformWeight *dw = BKE_defvert_find_index(&dvert[i], defgrp_index);
297         if (dw) {
298           tdw1[numIdx] = dw;
299           tdw2[numIdx] = (defgrp_index_other >= 0) ?
300                              BKE_defvert_find_index(&dvert[i], defgrp_index_other) :
301                              NULL;
302           tidx[numIdx++] = i;
303         }
304       }
305       break;
306     case MOD_WVG_SET_B:
307       /* All vertices in second vgroup. */
308       for (i = 0; i < numVerts; i++) {
309         MDeformWeight *dw = (defgrp_index_other >= 0) ?
310                                 BKE_defvert_find_index(&dvert[i], defgrp_index_other) :
311                                 NULL;
312         if (dw) {
313           tdw1[numIdx] = BKE_defvert_find_index(&dvert[i], defgrp_index);
314           tdw2[numIdx] = dw;
315           tidx[numIdx++] = i;
316         }
317       }
318       break;
319     case MOD_WVG_SET_OR:
320       /* All vertices in one vgroup or the other. */
321       for (i = 0; i < numVerts; i++) {
322         MDeformWeight *adw = BKE_defvert_find_index(&dvert[i], defgrp_index);
323         MDeformWeight *bdw = (defgrp_index_other >= 0) ?
324                                  BKE_defvert_find_index(&dvert[i], defgrp_index_other) :
325                                  NULL;
326         if (adw || bdw) {
327           tdw1[numIdx] = adw;
328           tdw2[numIdx] = bdw;
329           tidx[numIdx++] = i;
330         }
331       }
332       break;
333     case MOD_WVG_SET_AND:
334       /* All vertices in both vgroups. */
335       for (i = 0; i < numVerts; i++) {
336         MDeformWeight *adw = BKE_defvert_find_index(&dvert[i], defgrp_index);
337         MDeformWeight *bdw = (defgrp_index_other >= 0) ?
338                                  BKE_defvert_find_index(&dvert[i], defgrp_index_other) :
339                                  NULL;
340         if (adw && bdw) {
341           tdw1[numIdx] = adw;
342           tdw2[numIdx] = bdw;
343           tidx[numIdx++] = i;
344         }
345       }
346       break;
347     case MOD_WVG_SET_ALL:
348     default:
349       /* Use all vertices. */
350       for (i = 0; i < numVerts; i++) {
351         tdw1[i] = BKE_defvert_find_index(&dvert[i], defgrp_index);
352         tdw2[i] = (defgrp_index_other >= 0) ?
353                       BKE_defvert_find_index(&dvert[i], defgrp_index_other) :
354                       NULL;
355       }
356       numIdx = -1;
357       break;
358   }
359   if (numIdx == 0) {
360     /* Use no vertices! Hence, return org data. */
361     MEM_freeN(tdw1);
362     MEM_freeN(tdw2);
363     MEM_freeN(tidx);
364     return mesh;
365   }
366   if (numIdx != -1) {
367     indices = MEM_malloc_arrayN(numIdx, sizeof(int), "WeightVGMix Modifier, indices");
368     memcpy(indices, tidx, sizeof(int) * numIdx);
369     dw1 = MEM_malloc_arrayN(numIdx, sizeof(MDeformWeight *), "WeightVGMix Modifier, dw1");
370     memcpy(dw1, tdw1, sizeof(MDeformWeight *) * numIdx);
371     MEM_freeN(tdw1);
372     dw2 = MEM_malloc_arrayN(numIdx, sizeof(MDeformWeight *), "WeightVGMix Modifier, dw2");
373     memcpy(dw2, tdw2, sizeof(MDeformWeight *) * numIdx);
374     MEM_freeN(tdw2);
375   }
376   else {
377     /* Use all vertices. */
378     numIdx = numVerts;
379     /* Just copy MDeformWeight pointers arrays, they will be freed at the end. */
380     dw1 = tdw1;
381     dw2 = tdw2;
382   }
383   MEM_freeN(tidx);
384
385   org_w = MEM_malloc_arrayN(numIdx, sizeof(float), "WeightVGMix Modifier, org_w");
386   new_w = MEM_malloc_arrayN(numIdx, sizeof(float), "WeightVGMix Modifier, new_w");
387
388   /* Mix weights. */
389   for (i = 0; i < numIdx; i++) {
390     float weight2;
391     if (invert_vgroup_a) {
392       org_w[i] = 1.0f - (dw1[i] ? dw1[i]->weight : wmd->default_weight_a);
393     }
394     else {
395       org_w[i] = dw1[i] ? dw1[i]->weight : wmd->default_weight_a;
396     }
397     if (invert_vgroup_b) {
398       weight2 = 1.0f - (dw2[i] ? dw2[i]->weight : wmd->default_weight_b);
399     }
400     else {
401       weight2 = dw2[i] ? dw2[i]->weight : wmd->default_weight_b;
402     }
403
404     new_w[i] = mix_weight(org_w[i], weight2, wmd->mix_mode);
405   }
406
407   /* Do masking. */
408   struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
409   weightvg_do_mask(ctx,
410                    numIdx,
411                    indices,
412                    org_w,
413                    new_w,
414                    ctx->object,
415                    mesh,
416                    wmd->mask_constant,
417                    wmd->mask_defgrp_name,
418                    scene,
419                    wmd->mask_texture,
420                    wmd->mask_tex_use_channel,
421                    wmd->mask_tex_mapping,
422                    wmd->mask_tex_map_obj,
423                    wmd->mask_tex_map_bone,
424                    wmd->mask_tex_uvlayer_name,
425                    invert_vgroup_mask);
426
427   /* Update (add to) vgroup.
428    * XXX Depending on the MOD_WVG_SET_xxx option chosen, we might have to add vertices to vgroup.
429    */
430   weightvg_update_vg(
431       dvert, defgrp_index, dw1, numIdx, indices, org_w, true, -FLT_MAX, false, 0.0f, do_normalize);
432
433   /* If weight preview enabled... */
434 #if 0 /* XXX Currently done in mod stack :/ */
435   if (do_prev) {
436     DM_update_weight_mcol(ob, dm, 0, org_w, numIdx, indices);
437   }
438 #endif
439
440   /* Freeing stuff. */
441   MEM_freeN(org_w);
442   MEM_freeN(new_w);
443   MEM_freeN(dw1);
444   MEM_freeN(dw2);
445   MEM_SAFE_FREE(indices);
446
447   mesh->runtime.is_original = false;
448
449   /* Return the vgroup-modified mesh. */
450   return mesh;
451 }
452
453 static void panel_draw(const bContext *UNUSED(C), Panel *panel)
454 {
455   uiLayout *layout = panel->layout;
456
457   PointerRNA ob_ptr;
458   PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
459
460   uiLayoutSetPropSep(layout, true);
461
462   modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group_a", "invert_vertex_group_a", NULL);
463   modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group_b", "invert_vertex_group_b", IFACE_("B"));
464
465   uiItemS(layout);
466
467   uiItemR(layout, ptr, "default_weight_a", 0, NULL, ICON_NONE);
468   uiItemR(layout, ptr, "default_weight_b", 0, IFACE_("B"), ICON_NONE);
469
470   uiItemS(layout);
471
472   uiItemR(layout, ptr, "mix_set", 0, NULL, ICON_NONE);
473   uiItemR(layout, ptr, "mix_mode", 0, NULL, ICON_NONE);
474
475   uiItemR(layout, ptr, "normalize", 0, NULL, ICON_NONE);
476
477   modifier_panel_end(layout, ptr);
478 }
479
480 static void influence_panel_draw(const bContext *C, Panel *panel)
481 {
482   uiLayout *layout = panel->layout;
483
484   PointerRNA ob_ptr;
485   PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
486
487   weightvg_ui_common(C, &ob_ptr, ptr, layout);
488 }
489
490 static void panelRegister(ARegionType *region_type)
491 {
492   PanelType *panel_type = modifier_panel_register(
493       region_type, eModifierType_WeightVGMix, panel_draw);
494   modifier_subpanel_register(
495       region_type, "influence", "Influence", NULL, influence_panel_draw, panel_type);
496 }
497
498 ModifierTypeInfo modifierType_WeightVGMix = {
499     /* name */ "VertexWeightMix",
500     /* structName */ "WeightVGMixModifierData",
501     /* structSize */ sizeof(WeightVGMixModifierData),
502     /* srna */ &RNA_VertexWeightMixModifier,
503     /* type */ eModifierTypeType_NonGeometrical,
504     /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping |
505         eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_UsesPreview,
506     /* icon */ ICON_MOD_VERTEX_WEIGHT,
507
508     /* copyData */ BKE_modifier_copydata_generic,
509
510     /* deformVerts */ NULL,
511     /* deformMatrices */ NULL,
512     /* deformVertsEM */ NULL,
513     /* deformMatricesEM */ NULL,
514     /* modifyMesh */ modifyMesh,
515     /* modifyHair */ NULL,
516     /* modifyPointCloud */ NULL,
517     /* modifyVolume */ NULL,
518
519     /* initData */ initData,
520     /* requiredDataMask */ requiredDataMask,
521     /* freeData */ NULL,
522     /* isDisabled */ isDisabled,
523     /* updateDepsgraph */ updateDepsgraph,
524     /* dependsOnTime */ dependsOnTime,
525     /* dependsOnNormals */ NULL,
526     /* foreachIDLink */ foreachIDLink,
527     /* foreachTexLink */ foreachTexLink,
528     /* freeRuntimeData */ NULL,
529     /* panelRegister */ panelRegister,
530     /* blendWrite */ NULL,
531     /* blendRead */ NULL,
532 };