git blame: add file to help ignore cleanup commits
[blender.git] / source / blender / modifiers / intern / MOD_wave.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2005 by the Blender Foundation.
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup modifiers
22  */
23
24 #include "BLI_utildefines.h"
25
26 #include "BLI_math.h"
27
28 #include "BLT_translation.h"
29
30 #include "DNA_defaults.h"
31 #include "DNA_mesh_types.h"
32 #include "DNA_meshdata_types.h"
33 #include "DNA_object_types.h"
34 #include "DNA_scene_types.h"
35 #include "DNA_screen_types.h"
36
37 #include "BKE_context.h"
38 #include "BKE_deform.h"
39 #include "BKE_editmesh.h"
40 #include "BKE_lib_id.h"
41 #include "BKE_lib_query.h"
42 #include "BKE_mesh.h"
43 #include "BKE_mesh_wrapper.h"
44 #include "BKE_scene.h"
45 #include "BKE_screen.h"
46 #include "BKE_texture.h"
47
48 #include "UI_interface.h"
49 #include "UI_resources.h"
50
51 #include "RNA_access.h"
52
53 #include "MEM_guardedalloc.h"
54 #include "RE_shader_ext.h"
55
56 #include "MOD_modifiertypes.h"
57 #include "MOD_ui_common.h"
58 #include "MOD_util.h"
59
60 #include "DEG_depsgraph.h"
61 #include "DEG_depsgraph_query.h"
62
63 static void initData(ModifierData *md)
64 {
65   WaveModifierData *wmd = (WaveModifierData *)md;
66
67   BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(wmd, modifier));
68
69   MEMCPY_STRUCT_AFTER(wmd, DNA_struct_default_get(WaveModifierData), modifier);
70 }
71
72 static bool dependsOnTime(ModifierData *UNUSED(md))
73 {
74   return true;
75 }
76
77 static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
78 {
79   WaveModifierData *wmd = (WaveModifierData *)md;
80
81   walk(userData, ob, (ID **)&wmd->texture, IDWALK_CB_USER);
82   walk(userData, ob, (ID **)&wmd->objectcenter, IDWALK_CB_NOP);
83   walk(userData, ob, (ID **)&wmd->map_object, IDWALK_CB_NOP);
84 }
85
86 static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void *userData)
87 {
88   walk(userData, ob, md, "texture");
89 }
90
91 static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
92 {
93   WaveModifierData *wmd = (WaveModifierData *)md;
94   bool need_transform_relation = false;
95
96   if (wmd->objectcenter != NULL) {
97     DEG_add_object_relation(ctx->node, wmd->objectcenter, DEG_OB_COMP_TRANSFORM, "Wave Modifier");
98     need_transform_relation = true;
99   }
100
101   if (wmd->texture != NULL) {
102     DEG_add_generic_id_relation(ctx->node, &wmd->texture->id, "Wave Modifier");
103
104     if ((wmd->texmapping == MOD_DISP_MAP_OBJECT) && wmd->map_object != NULL) {
105       MOD_depsgraph_update_object_bone_relation(
106           ctx->node, wmd->map_object, wmd->map_bone, "Wave Modifier");
107       need_transform_relation = true;
108     }
109     else if (wmd->texmapping == MOD_DISP_MAP_GLOBAL) {
110       need_transform_relation = true;
111     }
112   }
113
114   if (need_transform_relation) {
115     DEG_add_modifier_to_transform_relation(ctx->node, "Wave Modifier");
116   }
117 }
118
119 static void requiredDataMask(Object *UNUSED(ob),
120                              ModifierData *md,
121                              CustomData_MeshMasks *r_cddata_masks)
122 {
123   WaveModifierData *wmd = (WaveModifierData *)md;
124
125   /* ask for UV coordinates if we need them */
126   if (wmd->texture && wmd->texmapping == MOD_DISP_MAP_UV) {
127     r_cddata_masks->fmask |= CD_MASK_MTFACE;
128   }
129
130   /* ask for vertexgroups if we need them */
131   if (wmd->defgrp_name[0] != '\0') {
132     r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
133   }
134 }
135
136 static bool dependsOnNormals(ModifierData *md)
137 {
138   WaveModifierData *wmd = (WaveModifierData *)md;
139
140   return (wmd->flag & MOD_WAVE_NORM) != 0;
141 }
142
143 static void waveModifier_do(WaveModifierData *md,
144                             const ModifierEvalContext *ctx,
145                             Object *ob,
146                             Mesh *mesh,
147                             float (*vertexCos)[3],
148                             int numVerts)
149 {
150   WaveModifierData *wmd = (WaveModifierData *)md;
151   MVert *mvert = NULL;
152   MDeformVert *dvert;
153   int defgrp_index;
154   float ctime = DEG_get_ctime(ctx->depsgraph);
155   float minfac = (float)(1.0 / exp(wmd->width * wmd->narrow * wmd->width * wmd->narrow));
156   float lifefac = wmd->height;
157   float(*tex_co)[3] = NULL;
158   const int wmd_axis = wmd->flag & (MOD_WAVE_X | MOD_WAVE_Y);
159   const float falloff = wmd->falloff;
160   float falloff_fac = 1.0f; /* when falloff == 0.0f this stays at 1.0f */
161   const bool invert_group = (wmd->flag & MOD_WAVE_INVERT_VGROUP) != 0;
162
163   if ((wmd->flag & MOD_WAVE_NORM) && (mesh != NULL)) {
164     mvert = mesh->mvert;
165   }
166
167   if (wmd->objectcenter != NULL) {
168     float mat[4][4];
169     /* get the control object's location in local coordinates */
170     invert_m4_m4(ob->imat, ob->obmat);
171     mul_m4_m4m4(mat, ob->imat, wmd->objectcenter->obmat);
172
173     wmd->startx = mat[3][0];
174     wmd->starty = mat[3][1];
175   }
176
177   /* get the index of the deform group */
178   MOD_get_vgroup(ob, mesh, wmd->defgrp_name, &dvert, &defgrp_index);
179
180   if (wmd->damp == 0.0f) {
181     wmd->damp = 10.0f;
182   }
183
184   if (wmd->lifetime != 0.0f) {
185     float x = ctime - wmd->timeoffs;
186
187     if (x > wmd->lifetime) {
188       lifefac = x - wmd->lifetime;
189
190       if (lifefac > wmd->damp) {
191         lifefac = 0.0;
192       }
193       else {
194         lifefac = (float)(wmd->height * (1.0f - sqrtf(lifefac / wmd->damp)));
195       }
196     }
197   }
198
199   Tex *tex_target = wmd->texture;
200   if (mesh != NULL && tex_target != NULL) {
201     tex_co = MEM_malloc_arrayN(numVerts, sizeof(*tex_co), "waveModifier_do tex_co");
202     MOD_get_texture_coords((MappingInfoModifierData *)wmd, ctx, ob, mesh, vertexCos, tex_co);
203
204     MOD_init_texture((MappingInfoModifierData *)wmd, ctx);
205   }
206
207   if (lifefac != 0.0f) {
208     /* avoid divide by zero checks within the loop */
209     float falloff_inv = falloff != 0.0f ? 1.0f / falloff : 1.0f;
210     int i;
211
212     for (i = 0; i < numVerts; i++) {
213       float *co = vertexCos[i];
214       float x = co[0] - wmd->startx;
215       float y = co[1] - wmd->starty;
216       float amplit = 0.0f;
217       float def_weight = 1.0f;
218
219       /* get weights */
220       if (dvert) {
221         def_weight = invert_group ? 1.0f - BKE_defvert_find_weight(&dvert[i], defgrp_index) :
222                                     BKE_defvert_find_weight(&dvert[i], defgrp_index);
223
224         /* if this vert isn't in the vgroup, don't deform it */
225         if (def_weight == 0.0f) {
226           continue;
227         }
228       }
229
230       switch (wmd_axis) {
231         case MOD_WAVE_X | MOD_WAVE_Y:
232           amplit = sqrtf(x * x + y * y);
233           break;
234         case MOD_WAVE_X:
235           amplit = x;
236           break;
237         case MOD_WAVE_Y:
238           amplit = y;
239           break;
240       }
241
242       /* this way it makes nice circles */
243       amplit -= (ctime - wmd->timeoffs) * wmd->speed;
244
245       if (wmd->flag & MOD_WAVE_CYCL) {
246         amplit = (float)fmodf(amplit - wmd->width, 2.0f * wmd->width) + wmd->width;
247       }
248
249       if (falloff != 0.0f) {
250         float dist = 0.0f;
251
252         switch (wmd_axis) {
253           case MOD_WAVE_X | MOD_WAVE_Y:
254             dist = sqrtf(x * x + y * y);
255             break;
256           case MOD_WAVE_X:
257             dist = fabsf(x);
258             break;
259           case MOD_WAVE_Y:
260             dist = fabsf(y);
261             break;
262         }
263
264         falloff_fac = (1.0f - (dist * falloff_inv));
265         CLAMP(falloff_fac, 0.0f, 1.0f);
266       }
267
268       /* GAUSSIAN */
269       if ((falloff_fac != 0.0f) && (amplit > -wmd->width) && (amplit < wmd->width)) {
270         amplit = amplit * wmd->narrow;
271         amplit = (float)(1.0f / expf(amplit * amplit) - minfac);
272
273         /*apply texture*/
274         if (tex_co) {
275           Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
276           TexResult texres;
277           texres.nor = NULL;
278           BKE_texture_get_value(scene, tex_target, tex_co[i], &texres, false);
279           amplit *= texres.tin;
280         }
281
282         /*apply weight & falloff */
283         amplit *= def_weight * falloff_fac;
284
285         if (mvert) {
286           /* move along normals */
287           if (wmd->flag & MOD_WAVE_NORM_X) {
288             co[0] += (lifefac * amplit) * mvert[i].no[0] / 32767.0f;
289           }
290           if (wmd->flag & MOD_WAVE_NORM_Y) {
291             co[1] += (lifefac * amplit) * mvert[i].no[1] / 32767.0f;
292           }
293           if (wmd->flag & MOD_WAVE_NORM_Z) {
294             co[2] += (lifefac * amplit) * mvert[i].no[2] / 32767.0f;
295           }
296         }
297         else {
298           /* move along local z axis */
299           co[2] += lifefac * amplit;
300         }
301       }
302     }
303   }
304
305   MEM_SAFE_FREE(tex_co);
306 }
307
308 static void deformVerts(ModifierData *md,
309                         const ModifierEvalContext *ctx,
310                         Mesh *mesh,
311                         float (*vertexCos)[3],
312                         int numVerts)
313 {
314   WaveModifierData *wmd = (WaveModifierData *)md;
315   Mesh *mesh_src = NULL;
316
317   if (wmd->flag & MOD_WAVE_NORM) {
318     mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, vertexCos, numVerts, true, false);
319   }
320   else if (wmd->texture != NULL || wmd->defgrp_name[0] != '\0') {
321     mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false);
322   }
323
324   waveModifier_do(wmd, ctx, ctx->object, mesh_src, vertexCos, numVerts);
325
326   if (!ELEM(mesh_src, NULL, mesh)) {
327     BKE_id_free(NULL, mesh_src);
328   }
329 }
330
331 static void deformVertsEM(ModifierData *md,
332                           const ModifierEvalContext *ctx,
333                           struct BMEditMesh *editData,
334                           Mesh *mesh,
335                           float (*vertexCos)[3],
336                           int numVerts)
337 {
338   WaveModifierData *wmd = (WaveModifierData *)md;
339   Mesh *mesh_src = NULL;
340
341   if (wmd->flag & MOD_WAVE_NORM) {
342     mesh_src = MOD_deform_mesh_eval_get(
343         ctx->object, editData, mesh, vertexCos, numVerts, true, false);
344   }
345   else if (wmd->texture != NULL || wmd->defgrp_name[0] != '\0') {
346     mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false);
347   }
348
349   /* TODO(Campbell): use edit-mode data only (remove this line). */
350   if (mesh_src != NULL) {
351     BKE_mesh_wrapper_ensure_mdata(mesh_src);
352   }
353
354   waveModifier_do(wmd, ctx, ctx->object, mesh_src, vertexCos, numVerts);
355
356   if (!ELEM(mesh_src, NULL, mesh)) {
357     BKE_id_free(NULL, mesh_src);
358   }
359 }
360
361 static void panel_draw(const bContext *UNUSED(C), Panel *panel)
362 {
363   uiLayout *sub, *row, *col;
364   uiLayout *layout = panel->layout;
365
366   PointerRNA ob_ptr;
367   PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
368
369   uiLayoutSetPropSep(layout, true);
370
371   row = uiLayoutRowWithHeading(layout, true, IFACE_("Motion"));
372   uiItemR(row, ptr, "use_x", UI_ITEM_R_TOGGLE | UI_ITEM_R_FORCE_BLANK_DECORATE, NULL, ICON_NONE);
373   uiItemR(row, ptr, "use_y", UI_ITEM_R_TOGGLE | UI_ITEM_R_FORCE_BLANK_DECORATE, NULL, ICON_NONE);
374
375   uiItemR(layout, ptr, "use_cyclic", 0, NULL, ICON_NONE);
376
377   row = uiLayoutRowWithHeading(layout, true, IFACE_("Along Normals"));
378   uiItemR(row, ptr, "use_normal", 0, "", ICON_NONE);
379   sub = uiLayoutRow(row, true);
380   uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_normal"));
381   uiItemR(sub, ptr, "use_normal_x", UI_ITEM_R_TOGGLE, "X", ICON_NONE);
382   uiItemR(sub, ptr, "use_normal_y", UI_ITEM_R_TOGGLE, "Y", ICON_NONE);
383   uiItemR(sub, ptr, "use_normal_z", UI_ITEM_R_TOGGLE, "Z", ICON_NONE);
384
385   col = uiLayoutColumn(layout, false);
386   uiItemR(col, ptr, "falloff_radius", 0, "Falloff", ICON_NONE);
387   uiItemR(col, ptr, "height", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
388   uiItemR(col, ptr, "width", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
389   uiItemR(col, ptr, "narrowness", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
390
391   modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL);
392
393   modifier_panel_end(layout, ptr);
394 }
395
396 static void position_panel_draw(const bContext *UNUSED(C), Panel *panel)
397 {
398   uiLayout *col;
399   uiLayout *layout = panel->layout;
400
401   PointerRNA *ptr = modifier_panel_get_property_pointers(panel, NULL);
402
403   uiLayoutSetPropSep(layout, true);
404
405   uiItemR(layout, ptr, "start_position_object", 0, IFACE_("Object"), ICON_NONE);
406
407   col = uiLayoutColumn(layout, true);
408   uiItemR(col, ptr, "start_position_x", 0, "Start Position X", ICON_NONE);
409   uiItemR(col, ptr, "start_position_y", 0, "Y", ICON_NONE);
410 }
411
412 static void time_panel_draw(const bContext *UNUSED(C), Panel *panel)
413 {
414   uiLayout *col;
415   uiLayout *layout = panel->layout;
416
417   PointerRNA *ptr = modifier_panel_get_property_pointers(panel, NULL);
418
419   uiLayoutSetPropSep(layout, true);
420
421   col = uiLayoutColumn(layout, false);
422   uiItemR(col, ptr, "time_offset", 0, "Offset", ICON_NONE);
423   uiItemR(col, ptr, "lifetime", 0, "Life", ICON_NONE);
424   uiItemR(col, ptr, "damping_time", 0, "Damping", ICON_NONE);
425   uiItemR(col, ptr, "speed", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
426 }
427
428 static void texture_panel_draw(const bContext *C, Panel *panel)
429 {
430   uiLayout *col;
431   uiLayout *layout = panel->layout;
432
433   PointerRNA ob_ptr;
434   PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
435
436   int texture_coords = RNA_enum_get(ptr, "texture_coords");
437
438   uiTemplateID(layout, C, ptr, "texture", "texture.new", NULL, NULL, 0, ICON_NONE, NULL);
439
440   uiLayoutSetPropSep(layout, true);
441
442   col = uiLayoutColumn(layout, false);
443   uiItemR(col, ptr, "texture_coords", 0, IFACE_("Coordinates"), ICON_NONE);
444   if (texture_coords == MOD_DISP_MAP_OBJECT) {
445     uiItemR(col, ptr, "texture_coords_object", 0, IFACE_("Object"), ICON_NONE);
446     PointerRNA texture_coords_obj_ptr = RNA_pointer_get(ptr, "texture_coords_object");
447     if (!RNA_pointer_is_null(&texture_coords_obj_ptr) &&
448         (RNA_enum_get(&texture_coords_obj_ptr, "type") == OB_ARMATURE)) {
449       PointerRNA texture_coords_obj_data_ptr = RNA_pointer_get(&texture_coords_obj_ptr, "data");
450       uiItemPointerR(col,
451                      ptr,
452                      "texture_coords_bone",
453                      &texture_coords_obj_data_ptr,
454                      "bones",
455                      IFACE_("Bone"),
456                      ICON_NONE);
457     }
458   }
459   else if (texture_coords == MOD_DISP_MAP_UV && RNA_enum_get(&ob_ptr, "type") == OB_MESH) {
460     PointerRNA obj_data_ptr = RNA_pointer_get(&ob_ptr, "data");
461     uiItemPointerR(col, ptr, "uv_layer", &obj_data_ptr, "uv_layers", NULL, ICON_NONE);
462   }
463 }
464
465 static void panelRegister(ARegionType *region_type)
466 {
467   PanelType *panel_type = modifier_panel_register(region_type, eModifierType_Wave, panel_draw);
468   modifier_subpanel_register(
469       region_type, "position", "Start Position", NULL, position_panel_draw, panel_type);
470   modifier_subpanel_register(region_type, "time", "Time", NULL, time_panel_draw, panel_type);
471   modifier_subpanel_register(
472       region_type, "texture", "Texture", NULL, texture_panel_draw, panel_type);
473 }
474
475 ModifierTypeInfo modifierType_Wave = {
476     /* name */ "Wave",
477     /* structName */ "WaveModifierData",
478     /* structSize */ sizeof(WaveModifierData),
479     /* srna */ &RNA_WaveModifier,
480     /* type */ eModifierTypeType_OnlyDeform,
481     /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsVertexCosOnly |
482         eModifierTypeFlag_SupportsEditmode,
483     /* icon */ ICON_MOD_WAVE,
484
485     /* copyData */ BKE_modifier_copydata_generic,
486
487     /* deformVerts */ deformVerts,
488     /* deformMatrices */ NULL,
489     /* deformVertsEM */ deformVertsEM,
490     /* deformMatricesEM */ NULL,
491     /* modifyMesh */ NULL,
492     /* modifyHair */ NULL,
493     /* modifyPointCloud */ NULL,
494     /* modifyVolume */ NULL,
495
496     /* initData */ initData,
497     /* requiredDataMask */ requiredDataMask,
498     /* freeData */ NULL,
499     /* isDisabled */ NULL,
500     /* updateDepsgraph */ updateDepsgraph,
501     /* dependsOnTime */ dependsOnTime,
502     /* dependsOnNormals */ dependsOnNormals,
503     /* foreachIDLink */ foreachIDLink,
504     /* foreachTexLink */ foreachTexLink,
505     /* freeRuntimeData */ NULL,
506     /* panelRegister */ panelRegister,
507     /* blendWrite */ NULL,
508     /* blendRead */ NULL,
509 };