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(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,
141                             struct Main *UNUSED(bmain),
142                             struct Scene *UNUSED(scene),
143                             Object *UNUSED(ob),
144                             struct DepsNodeHandle *node)
145 {
146         WarpModifierData *wmd = (WarpModifierData *) md;
147         if (wmd->object_from != NULL && wmd->object_to != NULL) {
148                 DEG_add_object_relation(node, wmd->object_from, DEG_OB_COMP_TRANSFORM, "Warp Modifier from");
149                 DEG_add_object_relation(node, wmd->object_to, DEG_OB_COMP_TRANSFORM, "Warp Modifier to");
150         }
151         if ((wmd->texmapping == MOD_DISP_MAP_OBJECT) && wmd->map_object != NULL) {
152                 DEG_add_object_relation(node, wmd->map_object, DEG_OB_COMP_TRANSFORM, "Warp Modifier map");
153         }
154 }
155
156 static void warpModifier_do(WarpModifierData *wmd, Object *ob,
157                             DerivedMesh *dm, float (*vertexCos)[3], int numVerts)
158 {
159         float obinv[4][4];
160         float mat_from[4][4];
161         float mat_from_inv[4][4];
162         float mat_to[4][4];
163         float mat_unit[4][4];
164         float mat_final[4][4];
165
166         float tmat[4][4];
167
168         const float falloff_radius_sq = SQUARE(wmd->falloff_radius);
169         float strength = wmd->strength;
170         float fac = 1.0f, weight;
171         int i;
172         int defgrp_index;
173         MDeformVert *dvert, *dv = NULL;
174
175         float (*tex_co)[3] = NULL;
176
177         if (!(wmd->object_from && wmd->object_to))
178                 return;
179
180         modifier_get_vgroup(ob, dm, wmd->defgrp_name, &dvert, &defgrp_index);
181         if (dvert == NULL) {
182                 defgrp_index = -1;
183         }
184
185         if (wmd->curfalloff == NULL) /* should never happen, but bad lib linking could cause it */
186                 wmd->curfalloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
187
188         if (wmd->curfalloff) {
189                 curvemapping_initialize(wmd->curfalloff);
190         }
191
192         invert_m4_m4(obinv, ob->obmat);
193
194         mul_m4_m4m4(mat_from, obinv, wmd->object_from->obmat);
195         mul_m4_m4m4(mat_to, obinv, wmd->object_to->obmat);
196
197         invert_m4_m4(tmat, mat_from); // swap?
198         mul_m4_m4m4(mat_final, tmat, mat_to);
199
200         invert_m4_m4(mat_from_inv, mat_from);
201
202         unit_m4(mat_unit);
203
204         if (strength < 0.0f) {
205                 float loc[3];
206                 strength = -strength;
207
208                 /* inverted location is not useful, just use the negative */
209                 copy_v3_v3(loc, mat_final[3]);
210                 invert_m4(mat_final);
211                 negate_v3_v3(mat_final[3], loc);
212
213         }
214         weight = strength;
215
216         if (wmd->texture) {
217                 tex_co = MEM_mallocN(sizeof(*tex_co) * numVerts, "warpModifier_do tex_co");
218                 get_texture_coords((MappingInfoModifierData *)wmd, ob, dm, vertexCos, tex_co, numVerts);
219
220                 modifier_init_texture(wmd->modifier.scene, wmd->texture);
221         }
222
223         for (i = 0; i < numVerts; i++) {
224                 float *co = vertexCos[i];
225
226                 if (wmd->falloff_type == eWarp_Falloff_None ||
227                     ((fac = len_squared_v3v3(co, mat_from[3])) < falloff_radius_sq &&
228                      (fac = (wmd->falloff_radius - sqrtf(fac)) / wmd->falloff_radius)))
229                 {
230                         /* skip if no vert group found */
231                         if (defgrp_index != -1) {
232                                 dv = &dvert[i];
233                                 weight = defvert_find_weight(dv, defgrp_index) * strength;
234                                 if (weight <= 0.0f) {
235                                         continue;
236                                 }
237                         }
238
239
240                         /* closely match PROP_SMOOTH and similar */
241                         switch (wmd->falloff_type) {
242                                 case eWarp_Falloff_None:
243                                         fac = 1.0f;
244                                         break;
245                                 case eWarp_Falloff_Curve:
246                                         fac = curvemapping_evaluateF(wmd->curfalloff, 0, fac);
247                                         break;
248                                 case eWarp_Falloff_Sharp:
249                                         fac = fac * fac;
250                                         break;
251                                 case eWarp_Falloff_Smooth:
252                                         fac = 3.0f * fac * fac - 2.0f * fac * fac * fac;
253                                         break;
254                                 case eWarp_Falloff_Root:
255                                         fac = sqrtf(fac);
256                                         break;
257                                 case eWarp_Falloff_Linear:
258                                         /* pass */
259                                         break;
260                                 case eWarp_Falloff_Const:
261                                         fac = 1.0f;
262                                         break;
263                                 case eWarp_Falloff_Sphere:
264                                         fac = sqrtf(2 * fac - fac * fac);
265                                         break;
266                                 case eWarp_Falloff_InvSquare:
267                                         fac = fac * (2.0f - fac);
268                                         break;
269                         }
270
271                         fac *= weight;
272
273                         if (tex_co) {
274                                 TexResult texres;
275                                 texres.nor = NULL;
276                                 BKE_texture_get_value(wmd->modifier.scene, wmd->texture, tex_co[i], &texres, false);
277                                 fac *= texres.tin;
278                         }
279
280                         if (fac != 0.0f) {
281                                 /* into the 'from' objects space */
282                                 mul_m4_v3(mat_from_inv, co);
283
284                                 if (fac == 1.0f) {
285                                         mul_m4_v3(mat_final, co);
286                                 }
287                                 else {
288                                         if (wmd->flag & MOD_WARP_VOLUME_PRESERVE) {
289                                                 /* interpolate the matrix for nicer locations */
290                                                 blend_m4_m4m4(tmat, mat_unit, mat_final, fac);
291                                                 mul_m4_v3(tmat, co);
292                                         }
293                                         else {
294                                                 float tvec[3];
295                                                 mul_v3_m4v3(tvec, mat_final, co);
296                                                 interp_v3_v3v3(co, co, tvec, fac);
297                                         }
298                                 }
299
300                                 /* out of the 'from' objects space */
301                                 mul_m4_v3(mat_from, co);
302                         }
303                 }
304         }
305
306         if (tex_co)
307                 MEM_freeN(tex_co);
308
309 }
310
311 static int warp_needs_dm(WarpModifierData *wmd)
312 {
313         return wmd->texture || wmd->defgrp_name[0];
314 }
315
316 static void deformVerts(ModifierData *md, Object *ob, DerivedMesh *derivedData,
317                         float (*vertexCos)[3], int numVerts, ModifierApplyFlag UNUSED(flag))
318 {
319         DerivedMesh *dm = NULL;
320         int use_dm = warp_needs_dm((WarpModifierData *)md);
321
322         if (use_dm) {
323                 dm = get_cddm(ob, NULL, derivedData, vertexCos, false);
324         }
325
326         warpModifier_do((WarpModifierData *)md, ob, dm, vertexCos, numVerts);
327
328         if (use_dm) {
329                 if (dm != derivedData) dm->release(dm);
330         }
331 }
332
333 static void deformVertsEM(ModifierData *md, Object *ob, struct BMEditMesh *em,
334                           DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
335 {
336         DerivedMesh *dm = derivedData;
337         int use_dm = warp_needs_dm((WarpModifierData *)md);
338
339         if (use_dm) {
340                 if (!derivedData)
341                         dm = CDDM_from_editbmesh(em, false, false);
342         }
343
344         deformVerts(md, ob, dm, vertexCos, numVerts, 0);
345
346         if (use_dm) {
347                 if (!derivedData) dm->release(dm);
348         }
349 }
350
351
352 ModifierTypeInfo modifierType_Warp = {
353         /* name */              "Warp",
354         /* structName */        "WarpModifierData",
355         /* structSize */        sizeof(WarpModifierData),
356         /* type */              eModifierTypeType_OnlyDeform,
357         /* flags */             eModifierTypeFlag_AcceptsCVs |
358                                 eModifierTypeFlag_AcceptsLattice |
359                                 eModifierTypeFlag_SupportsEditmode,
360         /* copyData */          copyData,
361         /* deformVerts */       deformVerts,
362         /* deformMatrices */    NULL,
363         /* deformVertsEM */     deformVertsEM,
364         /* deformMatricesEM */  NULL,
365         /* applyModifier */     NULL,
366         /* applyModifierEM */   NULL,
367         /* initData */          initData,
368         /* requiredDataMask */  requiredDataMask,
369         /* freeData */          freeData,
370         /* isDisabled */        isDisabled,
371         /* updateDepsgraph */   updateDepsgraph,
372         /* dependsOnTime */     dependsOnTime,
373         /* dependsOnNormals */  NULL,
374         /* foreachObjectLink */ foreachObjectLink,
375         /* foreachIDLink */     foreachIDLink,
376         /* foreachTexLink */    foreachTexLink,
377 };