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