Fix T58679: Missing modifiers update on changes to texture
[blender.git] / source / blender / modifiers / intern / MOD_warp.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software  Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Contributor(s): Campbell Barton
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  *
22  */
23
24 /** \file blender/modifiers/intern/MOD_warp.c
25  *  \ingroup modifiers
26  */
27
28 #include <string.h>
29
30 #include "MEM_guardedalloc.h"
31
32 #include "DNA_mesh_types.h"
33 #include "DNA_meshdata_types.h"
34 #include "DNA_object_types.h"
35
36 #include "BLI_math.h"
37 #include "BLI_utildefines.h"
38
39 #include "BKE_editmesh.h"
40 #include "BKE_library.h"
41 #include "BKE_library_query.h"
42 #include "BKE_mesh.h"
43 #include "BKE_modifier.h"
44 #include "BKE_deform.h"
45 #include "BKE_texture.h"
46 #include "BKE_colortools.h"
47
48 #include "DEG_depsgraph.h"
49 #include "DEG_depsgraph_query.h"
50
51 #include "RE_shader_ext.h"
52
53 #include "MOD_util.h"
54
55
56 static void initData(ModifierData *md)
57 {
58         WarpModifierData *wmd = (WarpModifierData *) md;
59
60         wmd->curfalloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
61         wmd->texture = NULL;
62         wmd->strength = 1.0f;
63         wmd->falloff_radius = 1.0f;
64         wmd->falloff_type = eWarp_Falloff_Smooth;
65         wmd->flag = 0;
66 }
67
68 static void copyData(const ModifierData *md, ModifierData *target, const int flag)
69 {
70         const WarpModifierData *wmd = (const WarpModifierData *) md;
71         WarpModifierData *twmd = (WarpModifierData *) target;
72
73         modifier_copyData_generic(md, target, flag);
74
75         twmd->curfalloff = curvemapping_copy(wmd->curfalloff);
76 }
77
78 static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
79 {
80         WarpModifierData *wmd = (WarpModifierData *)md;
81         CustomDataMask dataMask = 0;
82
83         /* ask for vertexgroups if we need them */
84         if (wmd->defgrp_name[0]) dataMask |= (CD_MASK_MDEFORMVERT);
85         dataMask |= (CD_MASK_MDEFORMVERT);
86
87         /* ask for UV coordinates if we need them */
88         if (wmd->texmapping == MOD_DISP_MAP_UV) dataMask |= (1 << CD_MTFACE);
89
90         return dataMask;
91 }
92
93 static bool dependsOnTime(ModifierData *md)
94 {
95         WarpModifierData *wmd = (WarpModifierData *)md;
96
97         if (wmd->texture) {
98                 return BKE_texture_dependsOnTime(wmd->texture);
99         }
100         else {
101                 return false;
102         }
103 }
104
105 static void freeData(ModifierData *md)
106 {
107         WarpModifierData *wmd = (WarpModifierData *) md;
108         curvemapping_free(wmd->curfalloff);
109 }
110
111
112 static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(userRenderParams))
113 {
114         WarpModifierData *wmd = (WarpModifierData *) md;
115
116         return !(wmd->object_from && wmd->object_to);
117 }
118
119 static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData)
120 {
121         WarpModifierData *wmd = (WarpModifierData *) md;
122
123         walk(userData, ob, &wmd->object_from, IDWALK_CB_NOP);
124         walk(userData, ob, &wmd->object_to, IDWALK_CB_NOP);
125         walk(userData, ob, &wmd->map_object, IDWALK_CB_NOP);
126 }
127
128 static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
129 {
130         WarpModifierData *wmd = (WarpModifierData *) md;
131
132         walk(userData, ob, (ID **)&wmd->texture, IDWALK_CB_USER);
133
134         foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
135 }
136
137 static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void *userData)
138 {
139         walk(userData, ob, md, "texture");
140 }
141
142 static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
143 {
144         WarpModifierData *wmd = (WarpModifierData *) md;
145         if (wmd->object_from != NULL && wmd->object_to != NULL) {
146                 DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Warplace Modifier");
147                 DEG_add_object_relation(ctx->node, wmd->object_from, DEG_OB_COMP_TRANSFORM, "Warp Modifier from");
148                 DEG_add_object_relation(ctx->node, wmd->object_to, DEG_OB_COMP_TRANSFORM, "Warp Modifier to");
149         }
150         if ((wmd->texmapping == MOD_DISP_MAP_OBJECT) && wmd->map_object != NULL) {
151                 DEG_add_object_relation(ctx->node, wmd->map_object, DEG_OB_COMP_TRANSFORM, "Warp Modifier map");
152         }
153         if (wmd->texture != NULL) {
154                 DEG_add_generic_id_relation(ctx->node, &wmd->texture->id, "Warp Modifier");
155         }
156 }
157
158 static void warpModifier_do(
159         WarpModifierData *wmd, const ModifierEvalContext *ctx,
160         Mesh *mesh, float (*vertexCos)[3], int numVerts)
161 {
162         Object *ob = ctx->object;
163         Depsgraph *depsgraph = ctx->depsgraph;
164         float obinv[4][4];
165         float mat_from[4][4];
166         float mat_from_inv[4][4];
167         float mat_to[4][4];
168         float mat_unit[4][4];
169         float mat_final[4][4];
170
171         float tmat[4][4];
172
173         const float falloff_radius_sq = SQUARE(wmd->falloff_radius);
174         float strength = wmd->strength;
175         float fac = 1.0f, weight;
176         int i;
177         int defgrp_index;
178         MDeformVert *dvert, *dv = NULL;
179
180         float (*tex_co)[3] = NULL;
181
182         if (!(wmd->object_from && wmd->object_to))
183                 return;
184
185         MOD_get_vgroup(ob, mesh, wmd->defgrp_name, &dvert, &defgrp_index);
186         if (dvert == NULL) {
187                 defgrp_index = -1;
188         }
189
190         if (wmd->curfalloff == NULL) /* should never happen, but bad lib linking could cause it */
191                 wmd->curfalloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
192
193         if (wmd->curfalloff) {
194                 curvemapping_initialize(wmd->curfalloff);
195         }
196
197         invert_m4_m4(obinv, ob->obmat);
198
199         mul_m4_m4m4(mat_from, obinv, wmd->object_from->obmat);
200         mul_m4_m4m4(mat_to, obinv, wmd->object_to->obmat);
201
202         invert_m4_m4(tmat, mat_from); // swap?
203         mul_m4_m4m4(mat_final, tmat, mat_to);
204
205         invert_m4_m4(mat_from_inv, mat_from);
206
207         unit_m4(mat_unit);
208
209         if (strength < 0.0f) {
210                 float loc[3];
211                 strength = -strength;
212
213                 /* inverted location is not useful, just use the negative */
214                 copy_v3_v3(loc, mat_final[3]);
215                 invert_m4(mat_final);
216                 negate_v3_v3(mat_final[3], loc);
217
218         }
219         weight = strength;
220
221         if (mesh != NULL && wmd->texture) {
222                 tex_co = MEM_malloc_arrayN(numVerts, sizeof(*tex_co), "warpModifier_do tex_co");
223                 MOD_get_texture_coords((MappingInfoModifierData *)wmd, ob, mesh, vertexCos, tex_co);
224
225                 MOD_init_texture(depsgraph, wmd->texture);
226         }
227
228         for (i = 0; i < numVerts; i++) {
229                 float *co = vertexCos[i];
230
231                 if (wmd->falloff_type == eWarp_Falloff_None ||
232                     ((fac = len_squared_v3v3(co, mat_from[3])) < falloff_radius_sq &&
233                      (fac = (wmd->falloff_radius - sqrtf(fac)) / wmd->falloff_radius)))
234                 {
235                         /* skip if no vert group found */
236                         if (defgrp_index != -1) {
237                                 dv = &dvert[i];
238                                 weight = defvert_find_weight(dv, defgrp_index) * strength;
239                                 if (weight <= 0.0f) {
240                                         continue;
241                                 }
242                         }
243
244
245                         /* closely match PROP_SMOOTH and similar */
246                         switch (wmd->falloff_type) {
247                                 case eWarp_Falloff_None:
248                                         fac = 1.0f;
249                                         break;
250                                 case eWarp_Falloff_Curve:
251                                         fac = curvemapping_evaluateF(wmd->curfalloff, 0, fac);
252                                         break;
253                                 case eWarp_Falloff_Sharp:
254                                         fac = fac * fac;
255                                         break;
256                                 case eWarp_Falloff_Smooth:
257                                         fac = 3.0f * fac * fac - 2.0f * fac * fac * fac;
258                                         break;
259                                 case eWarp_Falloff_Root:
260                                         fac = sqrtf(fac);
261                                         break;
262                                 case eWarp_Falloff_Linear:
263                                         /* pass */
264                                         break;
265                                 case eWarp_Falloff_Const:
266                                         fac = 1.0f;
267                                         break;
268                                 case eWarp_Falloff_Sphere:
269                                         fac = sqrtf(2 * fac - fac * fac);
270                                         break;
271                                 case eWarp_Falloff_InvSquare:
272                                         fac = fac * (2.0f - fac);
273                                         break;
274                         }
275
276                         fac *= weight;
277
278                         if (tex_co) {
279                                 struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
280                                 TexResult texres;
281                                 texres.nor = NULL;
282                                 BKE_texture_get_value(scene, wmd->texture, tex_co[i], &texres, false);
283                                 fac *= texres.tin;
284                         }
285
286                         if (fac != 0.0f) {
287                                 /* into the 'from' objects space */
288                                 mul_m4_v3(mat_from_inv, co);
289
290                                 if (fac == 1.0f) {
291                                         mul_m4_v3(mat_final, co);
292                                 }
293                                 else {
294                                         if (wmd->flag & MOD_WARP_VOLUME_PRESERVE) {
295                                                 /* interpolate the matrix for nicer locations */
296                                                 blend_m4_m4m4(tmat, mat_unit, mat_final, fac);
297                                                 mul_m4_v3(tmat, co);
298                                         }
299                                         else {
300                                                 float tvec[3];
301                                                 mul_v3_m4v3(tvec, mat_final, co);
302                                                 interp_v3_v3v3(co, co, tvec, fac);
303                                         }
304                                 }
305
306                                 /* out of the 'from' objects space */
307                                 mul_m4_v3(mat_from, co);
308                         }
309                 }
310         }
311
312         if (tex_co) {
313                 MEM_freeN(tex_co);
314         }
315 }
316
317 static void deformVerts(
318         ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh,
319         float (*vertexCos)[3], int numVerts)
320 {
321         WarpModifierData *wmd = (WarpModifierData *)md;
322         Mesh *mesh_src = NULL;
323
324         if (wmd->defgrp_name[0] != '\0' || wmd->texture != NULL) {
325                 /* mesh_src is only needed for vgroups and textures. */
326                 mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false);
327         }
328
329         warpModifier_do(wmd, ctx, mesh_src, vertexCos, numVerts);
330
331         if (!ELEM(mesh_src, NULL, mesh)) {
332                 BKE_id_free(NULL, mesh_src);
333         }
334 }
335
336 static void deformVertsEM(
337         ModifierData *md, const ModifierEvalContext *ctx, struct BMEditMesh *em,
338         Mesh *mesh, float (*vertexCos)[3], int numVerts)
339 {
340         WarpModifierData *wmd = (WarpModifierData *)md;
341         Mesh *mesh_src = NULL;
342
343         if (wmd->defgrp_name[0] != '\0' || wmd->texture != NULL) {
344                 /* mesh_src is only needed for vgroups and textures. */
345                 mesh_src = MOD_deform_mesh_eval_get(ctx->object, em, mesh, NULL, numVerts, false, false);
346         }
347
348         warpModifier_do(wmd, ctx, mesh_src, vertexCos, numVerts);
349
350         if (!ELEM(mesh_src, NULL, mesh)) {
351                 BKE_id_free(NULL, mesh_src);
352         }
353 }
354
355
356 ModifierTypeInfo modifierType_Warp = {
357         /* name */              "Warp",
358         /* structName */        "WarpModifierData",
359         /* structSize */        sizeof(WarpModifierData),
360         /* type */              eModifierTypeType_OnlyDeform,
361         /* flags */             eModifierTypeFlag_AcceptsCVs |
362                                 eModifierTypeFlag_AcceptsLattice |
363                                 eModifierTypeFlag_SupportsEditmode,
364         /* copyData */          copyData,
365
366         /* deformVerts_DM */    NULL,
367         /* deformMatrices_DM */ NULL,
368         /* deformVertsEM_DM */  NULL,
369         /* deformMatricesEM_DM*/NULL,
370         /* applyModifier_DM */  NULL,
371
372         /* deformVerts */       deformVerts,
373         /* deformMatrices */    NULL,
374         /* deformVertsEM */     deformVertsEM,
375         /* deformMatricesEM */  NULL,
376         /* applyModifier */     NULL,
377
378         /* initData */          initData,
379         /* requiredDataMask */  requiredDataMask,
380         /* freeData */          freeData,
381         /* isDisabled */        isDisabled,
382         /* updateDepsgraph */   updateDepsgraph,
383         /* dependsOnTime */     dependsOnTime,
384         /* dependsOnNormals */  NULL,
385         /* foreachObjectLink */ foreachObjectLink,
386         /* foreachIDLink */     foreachIDLink,
387         /* foreachTexLink */    foreachTexLink,
388 };