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_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 "RE_shader_ext.h"
49
50 #include "MOD_util.h"
51
52
53 static void initData(ModifierData *md)
54 {
55         WarpModifierData *wmd = (WarpModifierData *) md;
56
57         wmd->curfalloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
58         wmd->texture = NULL;
59         wmd->strength = 1.0f;
60         wmd->falloff_radius = 1.0f;
61         wmd->falloff_type = eWarp_Falloff_Smooth;
62         wmd->flag = 0;
63 }
64
65 static void copyData(const ModifierData *md, ModifierData *target)
66 {
67         const WarpModifierData *wmd = (const WarpModifierData *) md;
68         WarpModifierData *twmd = (WarpModifierData *) target;
69
70         modifier_copyData_generic(md, target);
71
72         twmd->curfalloff = curvemapping_copy(wmd->curfalloff);
73 }
74
75 static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
76 {
77         WarpModifierData *wmd = (WarpModifierData *)md;
78         CustomDataMask dataMask = 0;
79
80         /* ask for vertexgroups if we need them */
81         if (wmd->defgrp_name[0]) dataMask |= (CD_MASK_MDEFORMVERT);
82         dataMask |= (CD_MASK_MDEFORMVERT);
83
84         /* ask for UV coordinates if we need them */
85         if (wmd->texmapping == MOD_DISP_MAP_UV) dataMask |= (1 << CD_MTFACE);
86
87         return dataMask;
88 }
89
90 static bool dependsOnTime(ModifierData *md)
91 {
92         WarpModifierData *wmd = (WarpModifierData *)md;
93
94         if (wmd->texture) {
95                 return BKE_texture_dependsOnTime(wmd->texture);
96         }
97         else {
98                 return false;
99         }
100 }
101
102 static void freeData(ModifierData *md)
103 {
104         WarpModifierData *wmd = (WarpModifierData *) md;
105         curvemapping_free(wmd->curfalloff);
106 }
107
108
109 static bool isDisabled(ModifierData *md, int UNUSED(userRenderParams))
110 {
111         WarpModifierData *wmd = (WarpModifierData *) md;
112
113         return !(wmd->object_from && wmd->object_to);
114 }
115
116 static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData)
117 {
118         WarpModifierData *wmd = (WarpModifierData *) md;
119
120         walk(userData, ob, &wmd->object_from, IDWALK_CB_NOP);
121         walk(userData, ob, &wmd->object_to, IDWALK_CB_NOP);
122         walk(userData, ob, &wmd->map_object, IDWALK_CB_NOP);
123 }
124
125 static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
126 {
127         WarpModifierData *wmd = (WarpModifierData *) md;
128
129         walk(userData, ob, (ID **)&wmd->texture, IDWALK_CB_USER);
130
131         foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
132 }
133
134 static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void *userData)
135 {
136         walk(userData, ob, md, "texture");
137 }
138
139 static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
140 {
141         WarpModifierData *wmd = (WarpModifierData *) md;
142         if (wmd->object_from != NULL && wmd->object_to != NULL) {
143                 DEG_add_object_relation(ctx->node, wmd->object_from, DEG_OB_COMP_TRANSFORM, "Warp Modifier from");
144                 DEG_add_object_relation(ctx->node, wmd->object_to, DEG_OB_COMP_TRANSFORM, "Warp Modifier to");
145         }
146         if ((wmd->texmapping == MOD_DISP_MAP_OBJECT) && wmd->map_object != NULL) {
147                 DEG_add_object_relation(ctx->node, wmd->map_object, DEG_OB_COMP_TRANSFORM, "Warp Modifier map");
148         }
149 }
150
151 static void warpModifier_do(
152         WarpModifierData *wmd, Object *ob,
153         Mesh *mesh, 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_mesh(ob, mesh, 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_mesh((MappingInfoModifierData *)wmd, ob, mesh, vertexCos, tex_co);
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 void deformVerts(
308         ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh,
309         float (*vertexCos)[3], int numVerts)
310 {
311         Mesh *mesh_src = mesh;
312
313         if (mesh_src == NULL) {
314                 mesh_src = ctx->object->data;
315         }
316
317         BLI_assert(mesh_src->totvert == numVerts);
318
319         warpModifier_do((WarpModifierData *)md, ctx->object, mesh_src, vertexCos, numVerts);
320 }
321
322 static void deformVertsEM(
323         ModifierData *md, const ModifierEvalContext *ctx, struct BMEditMesh *em,
324         Mesh *mesh, float (*vertexCos)[3], int numVerts)
325 {
326         Mesh *mesh_src = mesh;
327
328         if (mesh_src == NULL) {
329                 mesh_src = BKE_bmesh_to_mesh_nomain(em->bm, &(struct BMeshToMeshParams){0});
330         }
331
332         BLI_assert(mesh_src->totvert == numVerts);
333
334         warpModifier_do((WarpModifierData *)md, ctx->object, mesh_src, vertexCos, numVerts);
335
336         if (!mesh) {
337                 BKE_id_free(NULL, mesh_src);
338         }
339 }
340
341
342 ModifierTypeInfo modifierType_Warp = {
343         /* name */              "Warp",
344         /* structName */        "WarpModifierData",
345         /* structSize */        sizeof(WarpModifierData),
346         /* type */              eModifierTypeType_OnlyDeform,
347         /* flags */             eModifierTypeFlag_AcceptsCVs |
348                                 eModifierTypeFlag_AcceptsLattice |
349                                 eModifierTypeFlag_SupportsEditmode,
350         /* copyData */          copyData,
351
352         /* deformVerts_DM */    NULL,
353         /* deformMatrices_DM */ NULL,
354         /* deformVertsEM_DM */  NULL,
355         /* deformMatricesEM_DM*/NULL,
356         /* applyModifier_DM */  NULL,
357         /* applyModifierEM_DM */NULL,
358
359         /* deformVerts */       deformVerts,
360         /* deformMatrices */    NULL,
361         /* deformVertsEM */     deformVertsEM,
362         /* deformMatricesEM */  NULL,
363         /* applyModifier */     NULL,
364         /* applyModifierEM */   NULL,
365
366         /* initData */          initData,
367         /* requiredDataMask */  requiredDataMask,
368         /* freeData */          freeData,
369         /* isDisabled */        isDisabled,
370         /* updateDepsgraph */   updateDepsgraph,
371         /* dependsOnTime */     dependsOnTime,
372         /* dependsOnNormals */  NULL,
373         /* foreachObjectLink */ foreachObjectLink,
374         /* foreachIDLink */     foreachIDLink,
375         /* foreachTexLink */    foreachTexLink,
376 };