Merge branch 'master' into blender2.8
[blender.git] / source / blender / modifiers / intern / MOD_wave.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  * The Original Code is Copyright (C) 2005 by the Blender Foundation.
19  * All rights reserved.
20  *
21  * Contributor(s): Daniel Dunbar
22  *                 Ton Roosendaal,
23  *                 Ben Batt,
24  *                 Brecht Van Lommel,
25  *                 Campbell Barton
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  *
29  */
30
31 /** \file blender/modifiers/intern/MOD_wave.c
32  *  \ingroup modifiers
33  */
34
35
36 #include "BLI_math.h"
37
38 #include "DNA_meshdata_types.h"
39 #include "DNA_scene_types.h"
40 #include "DNA_object_types.h"
41
42 #include "BLI_utildefines.h"
43
44
45 #include "BKE_deform.h"
46 #include "BKE_DerivedMesh.h"
47 #include "BKE_library.h"
48 #include "BKE_library_query.h"
49 #include "BKE_scene.h"
50 #include "BKE_texture.h"
51
52 #include "MEM_guardedalloc.h"
53 #include "RE_shader_ext.h"
54
55 #include "MOD_modifiertypes.h"
56 #include "MOD_util.h"
57
58 #include "DEG_depsgraph.h"
59 #include "DEG_depsgraph_query.h"
60
61 static void initData(ModifierData *md)
62 {
63         WaveModifierData *wmd = (WaveModifierData *) md; // whadya know, moved here from Iraq
64
65         wmd->flag |= (MOD_WAVE_X | MOD_WAVE_Y | MOD_WAVE_CYCL |
66                       MOD_WAVE_NORM_X | MOD_WAVE_NORM_Y | MOD_WAVE_NORM_Z);
67
68         wmd->objectcenter = NULL;
69         wmd->texture = NULL;
70         wmd->map_object = NULL;
71         wmd->height = 0.5f;
72         wmd->width = 1.5f;
73         wmd->speed = 0.25f;
74         wmd->narrow = 1.5f;
75         wmd->lifetime = 0.0f;
76         wmd->damp = 10.0f;
77         wmd->falloff = 0.0f;
78         wmd->texmapping = MOD_DISP_MAP_LOCAL;
79         wmd->defgrp_name[0] = 0;
80 }
81
82 static bool dependsOnTime(ModifierData *UNUSED(md))
83 {
84         return true;
85 }
86
87 static void foreachObjectLink(
88         ModifierData *md, Object *ob,
89         ObjectWalkFunc walk, void *userData)
90 {
91         WaveModifierData *wmd = (WaveModifierData *) md;
92
93         walk(userData, ob, &wmd->objectcenter, IDWALK_CB_NOP);
94         walk(userData, ob, &wmd->map_object, IDWALK_CB_NOP);
95 }
96
97 static void foreachIDLink(ModifierData *md, Object *ob,
98                           IDWalkFunc walk, void *userData)
99 {
100         WaveModifierData *wmd = (WaveModifierData *) md;
101
102         walk(userData, ob, (ID **)&wmd->texture, IDWALK_CB_USER);
103
104         foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
105 }
106
107 static void foreachTexLink(ModifierData *md, Object *ob,
108                            TexWalkFunc walk, void *userData)
109 {
110         walk(userData, ob, md, "texture");
111 }
112
113 static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
114 {
115         WaveModifierData *wmd = (WaveModifierData *)md;
116         if (wmd->objectcenter != NULL) {
117                 DEG_add_object_relation(ctx->node, wmd->objectcenter, DEG_OB_COMP_TRANSFORM, "Wave Modifier");
118         }
119         if (wmd->map_object != NULL) {
120                 DEG_add_object_relation(ctx->node, wmd->map_object, DEG_OB_COMP_TRANSFORM, "Wave Modifier");
121         }
122 }
123
124 static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
125 {
126         WaveModifierData *wmd = (WaveModifierData *)md;
127         CustomDataMask dataMask = 0;
128
129
130         /* ask for UV coordinates if we need them */
131         if (wmd->texture && wmd->texmapping == MOD_DISP_MAP_UV)
132                 dataMask |= CD_MASK_MTFACE;
133
134         /* ask for vertexgroups if we need them */
135         if (wmd->defgrp_name[0])
136                 dataMask |= CD_MASK_MDEFORMVERT;
137
138         return dataMask;
139 }
140
141 static void waveModifier_do(WaveModifierData *md,
142                             Depsgraph *depsgraph,
143                             Object *ob, DerivedMesh *dm,
144                             float (*vertexCos)[3], int numVerts)
145 {
146         WaveModifierData *wmd = (WaveModifierData *) md;
147         MVert *mvert = NULL;
148         MDeformVert *dvert;
149         int defgrp_index;
150         float ctime = DEG_get_ctime(depsgraph);
151         float minfac = (float)(1.0 / exp(wmd->width * wmd->narrow * wmd->width * wmd->narrow));
152         float lifefac = wmd->height;
153         float (*tex_co)[3] = NULL;
154         const int wmd_axis = wmd->flag & (MOD_WAVE_X | MOD_WAVE_Y);
155         const float falloff = wmd->falloff;
156         float falloff_fac = 1.0f; /* when falloff == 0.0f this stays at 1.0f */
157
158         if ((wmd->flag & MOD_WAVE_NORM) && (ob->type == OB_MESH))
159                 mvert = dm->getVertArray(dm);
160
161         if (wmd->objectcenter) {
162                 float mat[4][4];
163                 /* get the control object's location in local coordinates */
164                 invert_m4_m4(ob->imat, ob->obmat);
165                 mul_m4_m4m4(mat, ob->imat, wmd->objectcenter->obmat);
166
167                 wmd->startx = mat[3][0];
168                 wmd->starty = mat[3][1];
169         }
170
171         /* get the index of the deform group */
172         modifier_get_vgroup(ob, dm, wmd->defgrp_name, &dvert, &defgrp_index);
173
174         if (wmd->damp == 0) wmd->damp = 10.0f;
175
176         if (wmd->lifetime != 0.0f) {
177                 float x = ctime - wmd->timeoffs;
178
179                 if (x > wmd->lifetime) {
180                         lifefac = x - wmd->lifetime;
181
182                         if (lifefac > wmd->damp) lifefac = 0.0;
183                         else lifefac = (float)(wmd->height * (1.0f - sqrtf(lifefac / wmd->damp)));
184                 }
185         }
186
187         if (wmd->texture) {
188                 tex_co = MEM_malloc_arrayN(numVerts, sizeof(*tex_co),
189                                      "waveModifier_do tex_co");
190                 get_texture_coords((MappingInfoModifierData *)wmd, ob, dm, vertexCos, tex_co, numVerts);
191
192                 modifier_init_texture(wmd->modifier.scene, wmd->texture);
193         }
194
195         if (lifefac != 0.0f) {
196                 /* avoid divide by zero checks within the loop */
197                 float falloff_inv = falloff ? 1.0f / falloff : 1.0f;
198                 int i;
199
200                 for (i = 0; i < numVerts; i++) {
201                         float *co = vertexCos[i];
202                         float x = co[0] - wmd->startx;
203                         float y = co[1] - wmd->starty;
204                         float amplit = 0.0f;
205                         float def_weight = 1.0f;
206
207                         /* get weights */
208                         if (dvert) {
209                                 def_weight = defvert_find_weight(&dvert[i], defgrp_index);
210
211                                 /* if this vert isn't in the vgroup, don't deform it */
212                                 if (def_weight == 0.0f) {
213                                         continue;
214                                 }
215                         }
216
217                         switch (wmd_axis) {
218                                 case MOD_WAVE_X | MOD_WAVE_Y:
219                                         amplit = sqrtf(x * x + y * y);
220                                         break;
221                                 case MOD_WAVE_X:
222                                         amplit = x;
223                                         break;
224                                 case MOD_WAVE_Y:
225                                         amplit = y;
226                                         break;
227                         }
228
229                         /* this way it makes nice circles */
230                         amplit -= (ctime - wmd->timeoffs) * wmd->speed;
231
232                         if (wmd->flag & MOD_WAVE_CYCL) {
233                                 amplit = (float)fmodf(amplit - wmd->width, 2.0f * wmd->width) +
234                                          wmd->width;
235                         }
236
237                         if (falloff != 0.0f) {
238                                 float dist = 0.0f;
239
240                                 switch (wmd_axis) {
241                                         case MOD_WAVE_X | MOD_WAVE_Y:
242                                                 dist = sqrtf(x * x + y * y);
243                                                 break;
244                                         case MOD_WAVE_X:
245                                                 dist = fabsf(x);
246                                                 break;
247                                         case MOD_WAVE_Y:
248                                                 dist = fabsf(y);
249                                                 break;
250                                 }
251
252                                 falloff_fac = (1.0f - (dist * falloff_inv));
253                                 CLAMP(falloff_fac, 0.0f, 1.0f);
254                         }
255
256                         /* GAUSSIAN */
257                         if ((falloff_fac != 0.0f) && (amplit > -wmd->width) && (amplit < wmd->width)) {
258                                 amplit = amplit * wmd->narrow;
259                                 amplit = (float)(1.0f / expf(amplit * amplit) - minfac);
260
261                                 /*apply texture*/
262                                 if (wmd->texture) {
263                                         TexResult texres;
264                                         texres.nor = NULL;
265                                         BKE_texture_get_value(wmd->modifier.scene, wmd->texture, tex_co[i], &texres, false);
266                                         amplit *= texres.tin;
267                                 }
268
269                                 /*apply weight & falloff */
270                                 amplit *= def_weight * falloff_fac;
271
272                                 if (mvert) {
273                                         /* move along normals */
274                                         if (wmd->flag & MOD_WAVE_NORM_X) {
275                                                 co[0] += (lifefac * amplit) * mvert[i].no[0] / 32767.0f;
276                                         }
277                                         if (wmd->flag & MOD_WAVE_NORM_Y) {
278                                                 co[1] += (lifefac * amplit) * mvert[i].no[1] / 32767.0f;
279                                         }
280                                         if (wmd->flag & MOD_WAVE_NORM_Z) {
281                                                 co[2] += (lifefac * amplit) * mvert[i].no[2] / 32767.0f;
282                                         }
283                                 }
284                                 else {
285                                         /* move along local z axis */
286                                         co[2] += lifefac * amplit;
287                                 }
288                         }
289                 }
290         }
291
292         if (wmd->texture) MEM_freeN(tex_co);
293 }
294
295 static void deformVerts(ModifierData *md, const ModifierEvalContext *ctx,
296                         DerivedMesh *derivedData,
297                         float (*vertexCos)[3],
298                         int numVerts)
299 {
300         DerivedMesh *dm = derivedData;
301         WaveModifierData *wmd = (WaveModifierData *)md;
302
303         if (wmd->flag & MOD_WAVE_NORM)
304                 dm = get_cddm(ctx->object, NULL, dm, vertexCos, false);
305         else if (wmd->texture || wmd->defgrp_name[0])
306                 dm = get_dm(ctx->object, NULL, dm, NULL, false, false);
307
308         waveModifier_do(wmd, ctx->depsgraph, ctx->object, dm, vertexCos, numVerts);
309
310         if (dm != derivedData)
311                 dm->release(dm);
312 }
313
314 static void deformVertsEM(
315         ModifierData *md, const ModifierEvalContext *ctx,
316         struct BMEditMesh *editData,
317         DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
318 {
319         DerivedMesh *dm = derivedData;
320         WaveModifierData *wmd = (WaveModifierData *)md;
321
322         if (wmd->flag & MOD_WAVE_NORM)
323                 dm = get_cddm(ctx->object, editData, dm, vertexCos, false);
324         else if (wmd->texture || wmd->defgrp_name[0])
325                 dm = get_dm(ctx->object, editData, dm, NULL, false, false);
326
327         waveModifier_do(wmd, ctx->depsgraph, ctx->object, dm, vertexCos, numVerts);
328
329         if (dm != derivedData)
330                 dm->release(dm);
331 }
332
333
334 ModifierTypeInfo modifierType_Wave = {
335         /* name */              "Wave",
336         /* structName */        "WaveModifierData",
337         /* structSize */        sizeof(WaveModifierData),
338         /* type */              eModifierTypeType_OnlyDeform,
339         /* flags */             eModifierTypeFlag_AcceptsCVs |
340                                 eModifierTypeFlag_AcceptsLattice |
341                                 eModifierTypeFlag_SupportsEditmode,
342
343         /* copyData */          modifier_copyData_generic,
344
345         /* deformVerts_DM */    deformVerts,
346         /* deformMatrices_DM */ NULL,
347         /* deformVertsEM_DM */  deformVertsEM,
348         /* deformMatricesEM_DM*/NULL,
349         /* applyModifier_DM */  NULL,
350         /* applyModifierEM_DM */NULL,
351
352         /* deformVerts */       NULL,
353         /* deformMatrices */    NULL,
354         /* deformVertsEM */     NULL,
355         /* deformMatricesEM */  NULL,
356         /* applyModifier */     NULL,
357         /* applyModifierEM */   NULL,
358
359         /* initData */          initData,
360         /* requiredDataMask */  requiredDataMask,
361         /* freeData */          NULL,
362         /* isDisabled */        NULL,
363         /* updateDepsgraph */   updateDepsgraph,
364         /* dependsOnTime */     dependsOnTime,
365         /* dependsOnNormals */  NULL,
366         /* foreachObjectLink */ foreachObjectLink,
367         /* foreachIDLink */     foreachIDLink,
368         /* foreachTexLink */    foreachTexLink,
369 };