Depsgraph: remove EvaluationContext, pass Depsgraph instead.
[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_object_types.h"
33 #include "DNA_meshdata_types.h"
34
35 #include "BLI_math.h"
36 #include "BLI_utildefines.h"
37
38 #include "BKE_cdderivedmesh.h"
39 #include "BKE_library_query.h"
40 #include "BKE_modifier.h"
41 #include "BKE_deform.h"
42 #include "BKE_texture.h"
43 #include "BKE_colortools.h"
44
45 #include "RE_shader_ext.h"
46
47 #include "MOD_util.h"
48
49
50 static void initData(ModifierData *md)
51 {
52         WarpModifierData *wmd = (WarpModifierData *) md;
53
54         wmd->curfalloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
55         wmd->texture = NULL;
56         wmd->strength = 1.0f;
57         wmd->falloff_radius = 1.0f;
58         wmd->falloff_type = eWarp_Falloff_Smooth;
59         wmd->flag = 0;
60 }
61
62 static void copyData(ModifierData *md, ModifierData *target)
63 {
64         WarpModifierData *wmd = (WarpModifierData *) md;
65         WarpModifierData *twmd = (WarpModifierData *) target;
66
67         if (twmd->curfalloff != NULL) {
68                 curvemapping_free(twmd->curfalloff);
69         }
70
71         modifier_copyData_generic(md, target);
72
73         twmd->curfalloff = curvemapping_copy(wmd->curfalloff);
74 }
75
76 static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
77 {
78         WarpModifierData *wmd = (WarpModifierData *)md;
79         CustomDataMask dataMask = 0;
80
81         /* ask for vertexgroups if we need them */
82         if (wmd->defgrp_name[0]) dataMask |= (CD_MASK_MDEFORMVERT);
83         dataMask |= (CD_MASK_MDEFORMVERT);
84
85         /* ask for UV coordinates if we need them */
86         if (wmd->texmapping == MOD_DISP_MAP_UV) dataMask |= (1 << CD_MTFACE);
87
88         return dataMask;
89 }
90
91 static bool dependsOnTime(ModifierData *md)
92 {
93         WarpModifierData *wmd = (WarpModifierData *)md;
94
95         if (wmd->texture) {
96                 return BKE_texture_dependsOnTime(wmd->texture);
97         }
98         else {
99                 return false;
100         }
101 }
102
103 static void freeData(ModifierData *md)
104 {
105         WarpModifierData *wmd = (WarpModifierData *) md;
106         curvemapping_free(wmd->curfalloff);
107 }
108
109
110 static bool isDisabled(ModifierData *md, int UNUSED(userRenderParams))
111 {
112         WarpModifierData *wmd = (WarpModifierData *) md;
113
114         return !(wmd->object_from && wmd->object_to);
115 }
116
117 static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData)
118 {
119         WarpModifierData *wmd = (WarpModifierData *) md;
120
121         walk(userData, ob, &wmd->object_from, IDWALK_CB_NOP);
122         walk(userData, ob, &wmd->object_to, IDWALK_CB_NOP);
123         walk(userData, ob, &wmd->map_object, IDWALK_CB_NOP);
124 }
125
126 static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
127 {
128         WarpModifierData *wmd = (WarpModifierData *) md;
129
130         walk(userData, ob, (ID **)&wmd->texture, IDWALK_CB_USER);
131
132         foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
133 }
134
135 static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void *userData)
136 {
137         walk(userData, ob, md, "texture");
138 }
139
140 static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
141 {
142         WarpModifierData *wmd = (WarpModifierData *) md;
143         if (wmd->object_from != NULL && wmd->object_to != NULL) {
144                 DEG_add_object_relation(ctx->node, wmd->object_from, DEG_OB_COMP_TRANSFORM, "Warp Modifier from");
145                 DEG_add_object_relation(ctx->node, wmd->object_to, DEG_OB_COMP_TRANSFORM, "Warp Modifier to");
146         }
147         if ((wmd->texmapping == MOD_DISP_MAP_OBJECT) && wmd->map_object != NULL) {
148                 DEG_add_object_relation(ctx->node, wmd->map_object, DEG_OB_COMP_TRANSFORM, "Warp Modifier map");
149         }
150 }
151
152 static void warpModifier_do(WarpModifierData *wmd, Object *ob,
153                             DerivedMesh *dm, float (*vertexCos)[3], int numVerts)
154 {
155         float obinv[4][4];
156         float mat_from[4][4];
157         float mat_from_inv[4][4];
158         float mat_to[4][4];
159         float mat_unit[4][4];
160         float mat_final[4][4];
161
162         float tmat[4][4];
163
164         const float falloff_radius_sq = SQUARE(wmd->falloff_radius);
165         float strength = wmd->strength;
166         float fac = 1.0f, weight;
167         int i;
168         int defgrp_index;
169         MDeformVert *dvert, *dv = NULL;
170
171         float (*tex_co)[3] = NULL;
172
173         if (!(wmd->object_from && wmd->object_to))
174                 return;
175
176         modifier_get_vgroup(ob, dm, wmd->defgrp_name, &dvert, &defgrp_index);
177         if (dvert == NULL) {
178                 defgrp_index = -1;
179         }
180
181         if (wmd->curfalloff == NULL) /* should never happen, but bad lib linking could cause it */
182                 wmd->curfalloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
183
184         if (wmd->curfalloff) {
185                 curvemapping_initialize(wmd->curfalloff);
186         }
187
188         invert_m4_m4(obinv, ob->obmat);
189
190         mul_m4_m4m4(mat_from, obinv, wmd->object_from->obmat);
191         mul_m4_m4m4(mat_to, obinv, wmd->object_to->obmat);
192
193         invert_m4_m4(tmat, mat_from); // swap?
194         mul_m4_m4m4(mat_final, tmat, mat_to);
195
196         invert_m4_m4(mat_from_inv, mat_from);
197
198         unit_m4(mat_unit);
199
200         if (strength < 0.0f) {
201                 float loc[3];
202                 strength = -strength;
203
204                 /* inverted location is not useful, just use the negative */
205                 copy_v3_v3(loc, mat_final[3]);
206                 invert_m4(mat_final);
207                 negate_v3_v3(mat_final[3], loc);
208
209         }
210         weight = strength;
211
212         if (wmd->texture) {
213                 tex_co = MEM_malloc_arrayN(numVerts, sizeof(*tex_co), "warpModifier_do tex_co");
214                 get_texture_coords((MappingInfoModifierData *)wmd, ob, dm, vertexCos, tex_co, numVerts);
215
216                 modifier_init_texture(wmd->modifier.scene, wmd->texture);
217         }
218
219         for (i = 0; i < numVerts; i++) {
220                 float *co = vertexCos[i];
221
222                 if (wmd->falloff_type == eWarp_Falloff_None ||
223                     ((fac = len_squared_v3v3(co, mat_from[3])) < falloff_radius_sq &&
224                      (fac = (wmd->falloff_radius - sqrtf(fac)) / wmd->falloff_radius)))
225                 {
226                         /* skip if no vert group found */
227                         if (defgrp_index != -1) {
228                                 dv = &dvert[i];
229                                 weight = defvert_find_weight(dv, defgrp_index) * strength;
230                                 if (weight <= 0.0f) {
231                                         continue;
232                                 }
233                         }
234
235
236                         /* closely match PROP_SMOOTH and similar */
237                         switch (wmd->falloff_type) {
238                                 case eWarp_Falloff_None:
239                                         fac = 1.0f;
240                                         break;
241                                 case eWarp_Falloff_Curve:
242                                         fac = curvemapping_evaluateF(wmd->curfalloff, 0, fac);
243                                         break;
244                                 case eWarp_Falloff_Sharp:
245                                         fac = fac * fac;
246                                         break;
247                                 case eWarp_Falloff_Smooth:
248                                         fac = 3.0f * fac * fac - 2.0f * fac * fac * fac;
249                                         break;
250                                 case eWarp_Falloff_Root:
251                                         fac = sqrtf(fac);
252                                         break;
253                                 case eWarp_Falloff_Linear:
254                                         /* pass */
255                                         break;
256                                 case eWarp_Falloff_Const:
257                                         fac = 1.0f;
258                                         break;
259                                 case eWarp_Falloff_Sphere:
260                                         fac = sqrtf(2 * fac - fac * fac);
261                                         break;
262                                 case eWarp_Falloff_InvSquare:
263                                         fac = fac * (2.0f - fac);
264                                         break;
265                         }
266
267                         fac *= weight;
268
269                         if (tex_co) {
270                                 TexResult texres;
271                                 texres.nor = NULL;
272                                 BKE_texture_get_value(wmd->modifier.scene, wmd->texture, tex_co[i], &texres, false);
273                                 fac *= texres.tin;
274                         }
275
276                         if (fac != 0.0f) {
277                                 /* into the 'from' objects space */
278                                 mul_m4_v3(mat_from_inv, co);
279
280                                 if (fac == 1.0f) {
281                                         mul_m4_v3(mat_final, co);
282                                 }
283                                 else {
284                                         if (wmd->flag & MOD_WARP_VOLUME_PRESERVE) {
285                                                 /* interpolate the matrix for nicer locations */
286                                                 blend_m4_m4m4(tmat, mat_unit, mat_final, fac);
287                                                 mul_m4_v3(tmat, co);
288                                         }
289                                         else {
290                                                 float tvec[3];
291                                                 mul_v3_m4v3(tvec, mat_final, co);
292                                                 interp_v3_v3v3(co, co, tvec, fac);
293                                         }
294                                 }
295
296                                 /* out of the 'from' objects space */
297                                 mul_m4_v3(mat_from, co);
298                         }
299                 }
300         }
301
302         if (tex_co)
303                 MEM_freeN(tex_co);
304
305 }
306
307 static int warp_needs_dm(WarpModifierData *wmd)
308 {
309         return wmd->texture || wmd->defgrp_name[0];
310 }
311
312 static void deformVerts(ModifierData *md, struct Depsgraph *UNUSED(depsgraph), Object *ob, DerivedMesh *derivedData,
313                         float (*vertexCos)[3], int numVerts, ModifierApplyFlag UNUSED(flag))
314 {
315         DerivedMesh *dm = NULL;
316         int use_dm = warp_needs_dm((WarpModifierData *)md);
317
318         if (use_dm) {
319                 dm = get_cddm(ob, NULL, derivedData, vertexCos, false);
320         }
321
322         warpModifier_do((WarpModifierData *)md, ob, dm, vertexCos, numVerts);
323
324         if (use_dm) {
325                 if (dm != derivedData) dm->release(dm);
326         }
327 }
328
329 static void deformVertsEM(ModifierData *md, struct Depsgraph *depsgraph, Object *ob, struct BMEditMesh *em,
330                           DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
331 {
332         DerivedMesh *dm = derivedData;
333         int use_dm = warp_needs_dm((WarpModifierData *)md);
334
335         if (use_dm) {
336                 if (!derivedData)
337                         dm = CDDM_from_editbmesh(em, false, false);
338         }
339
340         deformVerts(md, depsgraph, ob, dm, vertexCos, numVerts, 0);
341
342         if (use_dm) {
343                 if (!derivedData) dm->release(dm);
344         }
345 }
346
347
348 ModifierTypeInfo modifierType_Warp = {
349         /* name */              "Warp",
350         /* structName */        "WarpModifierData",
351         /* structSize */        sizeof(WarpModifierData),
352         /* type */              eModifierTypeType_OnlyDeform,
353         /* flags */             eModifierTypeFlag_AcceptsCVs |
354                                 eModifierTypeFlag_AcceptsLattice |
355                                 eModifierTypeFlag_SupportsEditmode,
356         /* copyData */          copyData,
357         /* deformVerts */       deformVerts,
358         /* deformMatrices */    NULL,
359         /* deformVertsEM */     deformVertsEM,
360         /* deformMatricesEM */  NULL,
361         /* applyModifier */     NULL,
362         /* applyModifierEM */   NULL,
363         /* initData */          initData,
364         /* requiredDataMask */  requiredDataMask,
365         /* freeData */          freeData,
366         /* isDisabled */        isDisabled,
367         /* updateDepsgraph */   updateDepsgraph,
368         /* dependsOnTime */     dependsOnTime,
369         /* dependsOnNormals */  NULL,
370         /* foreachObjectLink */ foreachObjectLink,
371         /* foreachIDLink */     foreachIDLink,
372         /* foreachTexLink */    foreachTexLink,
373 };