Recreating my GSoC branch.
[blender.git] / source / blender / modifiers / intern / MOD_wave.c
1 /*
2 * $Id$
3 *
4 * ***** BEGIN GPL LICENSE BLOCK *****
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software  Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 *
20 * The Original Code is Copyright (C) 2005 by the Blender Foundation.
21 * All rights reserved.
22 *
23 * Contributor(s): Daniel Dunbar
24 *                 Ton Roosendaal,
25 *                 Ben Batt,
26 *                 Brecht Van Lommel,
27 *                 Campbell Barton
28 *
29 * ***** END GPL LICENSE BLOCK *****
30 *
31 */
32
33 #include "BLI_math.h"
34
35 #include "DNA_meshdata_types.h"
36 #include "DNA_scene_types.h"
37
38 #include "BKE_DerivedMesh.h"
39 #include "BKE_object.h"
40 #include "BKE_deform.h"
41
42 #include "depsgraph_private.h"
43
44 #include "MEM_guardedalloc.h"
45 #include "RE_shader_ext.h"
46
47 #include "MOD_modifiertypes.h"
48 #include "MOD_util.h"
49
50 static void initData(ModifierData *md)
51 {
52         WaveModifierData *wmd = (WaveModifierData*) md; // whadya know, moved here from Iraq
53
54         wmd->flag |= (MOD_WAVE_X | MOD_WAVE_Y | MOD_WAVE_CYCL
55                         | MOD_WAVE_NORM_X | MOD_WAVE_NORM_Y | MOD_WAVE_NORM_Z);
56
57         wmd->objectcenter = NULL;
58         wmd->texture = NULL;
59         wmd->map_object = NULL;
60         wmd->height= 0.5f;
61         wmd->width= 1.5f;
62         wmd->speed= 0.25f;
63         wmd->narrow= 1.5f;
64         wmd->lifetime= 0.0f;
65         wmd->damp= 10.0f;
66         wmd->falloff= 0.0f;
67         wmd->texmapping = MOD_WAV_MAP_LOCAL;
68         wmd->defgrp_name[0] = 0;
69 }
70
71 static void copyData(ModifierData *md, ModifierData *target)
72 {
73         WaveModifierData *wmd = (WaveModifierData*) md;
74         WaveModifierData *twmd = (WaveModifierData*) target;
75
76         twmd->damp = wmd->damp;
77         twmd->flag = wmd->flag;
78         twmd->height = wmd->height;
79         twmd->lifetime = wmd->lifetime;
80         twmd->narrow = wmd->narrow;
81         twmd->speed = wmd->speed;
82         twmd->startx = wmd->startx;
83         twmd->starty = wmd->starty;
84         twmd->timeoffs = wmd->timeoffs;
85         twmd->width = wmd->width;
86         twmd->falloff = wmd->falloff;
87         twmd->objectcenter = wmd->objectcenter;
88         twmd->texture = wmd->texture;
89         twmd->map_object = wmd->map_object;
90         twmd->texmapping = wmd->texmapping;
91         strncpy(twmd->defgrp_name, wmd->defgrp_name, 32);
92 }
93
94 static int dependsOnTime(ModifierData *md)
95 {
96         return 1;
97 }
98
99 static void foreachObjectLink(
100                                            ModifierData *md, Object *ob,
101         ObjectWalkFunc walk, void *userData)
102 {
103         WaveModifierData *wmd = (WaveModifierData*) md;
104
105         walk(userData, ob, &wmd->objectcenter);
106         walk(userData, ob, &wmd->map_object);
107 }
108
109 static void foreachIDLink(ModifierData *md, Object *ob,
110                                            IDWalkFunc walk, void *userData)
111 {
112         WaveModifierData *wmd = (WaveModifierData*) md;
113
114         walk(userData, ob, (ID **)&wmd->texture);
115
116         foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
117 }
118
119 static void updateDepgraph(
120                                         ModifierData *md, DagForest *forest, Scene *scene, Object *ob,
121          DagNode *obNode)
122 {
123         WaveModifierData *wmd = (WaveModifierData*) md;
124
125         if(wmd->objectcenter) {
126                 DagNode *curNode = dag_get_node(forest, wmd->objectcenter);
127
128                 dag_add_relation(forest, curNode, obNode, DAG_RL_OB_DATA,
129                         "Wave Modifier");
130         }
131
132         if(wmd->map_object) {
133                 DagNode *curNode = dag_get_node(forest, wmd->map_object);
134
135                 dag_add_relation(forest, curNode, obNode, DAG_RL_OB_DATA,
136                         "Wave Modifer");
137         }
138 }
139
140 static CustomDataMask requiredDataMask(Object *ob, ModifierData *md)
141 {
142         WaveModifierData *wmd = (WaveModifierData *)md;
143         CustomDataMask dataMask = 0;
144
145
146         /* ask for UV coordinates if we need them */
147         if(wmd->texture && wmd->texmapping == MOD_WAV_MAP_UV)
148                 dataMask |= (1 << CD_MTFACE);
149
150         /* ask for vertexgroups if we need them */
151         if(wmd->defgrp_name[0])
152                 dataMask |= (1 << CD_MDEFORMVERT);
153
154         return dataMask;
155 }
156
157 static void wavemod_get_texture_coords(WaveModifierData *wmd, Object *ob,
158                                            DerivedMesh *dm,
159            float (*co)[3], float (*texco)[3],
160                    int numVerts)
161 {
162         int i;
163         int texmapping = wmd->texmapping;
164
165         if(texmapping == MOD_WAV_MAP_OBJECT) {
166                 if(wmd->map_object)
167                         invert_m4_m4(wmd->map_object->imat, wmd->map_object->obmat);
168                 else /* if there is no map object, default to local */
169                         texmapping = MOD_WAV_MAP_LOCAL;
170         }
171
172         /* UVs need special handling, since they come from faces */
173         if(texmapping == MOD_WAV_MAP_UV) {
174                 if(CustomData_has_layer(&dm->faceData, CD_MTFACE)) {
175                         MFace *mface = dm->getFaceArray(dm);
176                         MFace *mf;
177                         char *done = MEM_callocN(sizeof(*done) * numVerts,
178                                         "get_texture_coords done");
179                         int numFaces = dm->getNumFaces(dm);
180                         char uvname[32];
181                         MTFace *tf;
182
183                         validate_layer_name(&dm->faceData, CD_MTFACE, wmd->uvlayer_name, uvname);
184                         tf = CustomData_get_layer_named(&dm->faceData, CD_MTFACE, uvname);
185
186                         /* verts are given the UV from the first face that uses them */
187                         for(i = 0, mf = mface; i < numFaces; ++i, ++mf, ++tf) {
188                                 if(!done[mf->v1]) {
189                                         texco[mf->v1][0] = tf->uv[0][0];
190                                         texco[mf->v1][1] = tf->uv[0][1];
191                                         texco[mf->v1][2] = 0;
192                                         done[mf->v1] = 1;
193                                 }
194                                 if(!done[mf->v2]) {
195                                         texco[mf->v2][0] = tf->uv[1][0];
196                                         texco[mf->v2][1] = tf->uv[1][1];
197                                         texco[mf->v2][2] = 0;
198                                         done[mf->v2] = 1;
199                                 }
200                                 if(!done[mf->v3]) {
201                                         texco[mf->v3][0] = tf->uv[2][0];
202                                         texco[mf->v3][1] = tf->uv[2][1];
203                                         texco[mf->v3][2] = 0;
204                                         done[mf->v3] = 1;
205                                 }
206                                 if(!done[mf->v4]) {
207                                         texco[mf->v4][0] = tf->uv[3][0];
208                                         texco[mf->v4][1] = tf->uv[3][1];
209                                         texco[mf->v4][2] = 0;
210                                         done[mf->v4] = 1;
211                                 }
212                         }
213
214                         /* remap UVs from [0, 1] to [-1, 1] */
215                         for(i = 0; i < numVerts; ++i) {
216                                 texco[i][0] = texco[i][0] * 2 - 1;
217                                 texco[i][1] = texco[i][1] * 2 - 1;
218                         }
219
220                         MEM_freeN(done);
221                         return;
222                 } else /* if there are no UVs, default to local */
223                         texmapping = MOD_WAV_MAP_LOCAL;
224         }
225
226         for(i = 0; i < numVerts; ++i, ++co, ++texco) {
227                 switch(texmapping) {
228                         case MOD_WAV_MAP_LOCAL:
229                                 copy_v3_v3(*texco, *co);
230                                 break;
231                         case MOD_WAV_MAP_GLOBAL:
232                                 mul_v3_m4v3(*texco, ob->obmat, *co);
233                                 break;
234                         case MOD_WAV_MAP_OBJECT:
235                                 mul_v3_m4v3(*texco, ob->obmat, *co);
236                                 mul_m4_v3(wmd->map_object->imat, *texco);
237                                 break;
238                 }
239         }
240 }
241
242 static void waveModifier_do(WaveModifierData *md, 
243                 Scene *scene, Object *ob, DerivedMesh *dm,
244            float (*vertexCos)[3], int numVerts)
245 {
246         WaveModifierData *wmd = (WaveModifierData*) md;
247         MVert *mvert = NULL;
248         MDeformVert *dvert = NULL;
249         int defgrp_index;
250         float ctime = bsystem_time(scene, ob, (float)scene->r.cfra, 0.0);
251         float minfac =
252                         (float)(1.0 / exp(wmd->width * wmd->narrow * wmd->width * wmd->narrow));
253         float lifefac = wmd->height;
254         float (*tex_co)[3] = NULL;
255
256         if(wmd->flag & MOD_WAVE_NORM && ob->type == OB_MESH)
257                 mvert = dm->getVertArray(dm);
258
259         if(wmd->objectcenter){
260                 float mat[4][4];
261                 /* get the control object's location in local coordinates */
262                 invert_m4_m4(ob->imat, ob->obmat);
263                 mul_m4_m4m4(mat, wmd->objectcenter->obmat, ob->imat);
264
265                 wmd->startx = mat[3][0];
266                 wmd->starty = mat[3][1];
267         }
268
269         /* get the index of the deform group */
270         defgrp_index = defgroup_name_index(ob, wmd->defgrp_name);
271
272         if(defgrp_index >= 0){
273                 dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
274         }
275
276         if(wmd->damp == 0) wmd->damp = 10.0f;
277
278         if(wmd->lifetime != 0.0) {
279                 float x = ctime - wmd->timeoffs;
280
281                 if(x > wmd->lifetime) {
282                         lifefac = x - wmd->lifetime;
283
284                         if(lifefac > wmd->damp) lifefac = 0.0;
285                         else lifefac =
286                                 (float)(wmd->height * (1.0 - sqrt(lifefac / wmd->damp)));
287                 }
288         }
289
290         if(wmd->texture) {
291                 tex_co = MEM_mallocN(sizeof(*tex_co) * numVerts,
292                                          "waveModifier_do tex_co");
293                 wavemod_get_texture_coords(wmd, ob, dm, vertexCos, tex_co, numVerts);
294         }
295
296         if(lifefac != 0.0) {            
297                 /* avoid divide by zero checks within the loop */
298                 float falloff_inv= wmd->falloff ? 1.0f / wmd->falloff : 1.0;
299                 int i;
300
301                 for(i = 0; i < numVerts; i++) {
302                         float *co = vertexCos[i];
303                         float x = co[0] - wmd->startx;
304                         float y = co[1] - wmd->starty;
305                         float amplit= 0.0f;
306                         float dist = 0.0f;
307                         float falloff_fac = 0.0f;
308                         TexResult texres;
309                         MDeformWeight *def_weight = NULL;
310
311                         /* get weights */
312                         if(dvert) {
313                                 int j;
314                                 for(j = 0; j < dvert[i].totweight; ++j) {
315                                         if(dvert[i].dw[j].def_nr == defgrp_index) {
316                                                 def_weight = &dvert[i].dw[j];
317                                                 break;
318                                         }
319                                 }
320
321                                 /* if this vert isn't in the vgroup, don't deform it */
322                                 if(!def_weight) continue;
323                         }
324
325                         if(wmd->texture) {
326                                 texres.nor = NULL;
327                                 get_texture_value(wmd->texture, tex_co[i], &texres);
328                         }
329
330                         /*get dist*/
331                         if(wmd->flag & MOD_WAVE_X) {
332                                 if(wmd->flag & MOD_WAVE_Y){
333                                         dist = (float)sqrt(x*x + y*y);
334                                 }
335                                 else{
336                                         dist = fabs(x);
337                                 }
338                         }
339                         else if(wmd->flag & MOD_WAVE_Y) {
340                                 dist = fabs(y);
341                         }
342
343                         falloff_fac = (1.0f - (dist * falloff_inv));
344
345                         if(wmd->flag & MOD_WAVE_X) {
346                                 if(wmd->flag & MOD_WAVE_Y) amplit = (float)sqrt(x*x + y*y);
347                                 else amplit = x;
348                         }
349                         else if(wmd->flag & MOD_WAVE_Y)
350                                 amplit= y;
351
352                         /* this way it makes nice circles */
353                         amplit -= (ctime - wmd->timeoffs) * wmd->speed;
354
355                         if(wmd->flag & MOD_WAVE_CYCL) {
356                                 amplit = (float)fmod(amplit - wmd->width, 2.0 * wmd->width)
357                                                 + wmd->width;
358                         }
359
360                         /* GAUSSIAN */
361                         if(amplit > -wmd->width && amplit < wmd->width) {
362                                 amplit = amplit * wmd->narrow;
363                                 amplit = (float)(1.0 / exp(amplit * amplit) - minfac);
364
365                                 /*apply texture*/
366                                 if(wmd->texture)
367                                         amplit = amplit * texres.tin;
368
369                                 /*apply weight*/
370                                 if(def_weight)
371                                         amplit = amplit * def_weight->weight;
372
373                                 /*apply falloff*/
374                                 if (wmd->falloff > 0)
375                                         amplit = amplit * falloff_fac;
376
377                                 if(mvert) {
378                                         /* move along normals */
379                                         if(wmd->flag & MOD_WAVE_NORM_X) {
380                                                 co[0] += (lifefac * amplit) * mvert[i].no[0] / 32767.0f;
381                                         }
382                                         if(wmd->flag & MOD_WAVE_NORM_Y) {
383                                                 co[1] += (lifefac * amplit) * mvert[i].no[1] / 32767.0f;
384                                         }
385                                         if(wmd->flag & MOD_WAVE_NORM_Z) {
386                                                 co[2] += (lifefac * amplit) * mvert[i].no[2] / 32767.0f;
387                                         }
388                                 }
389                                 else {
390                                         /* move along local z axis */
391                                         co[2] += lifefac * amplit;
392                                 }
393                         }
394                 }
395         }
396
397         if(wmd->texture) MEM_freeN(tex_co);
398 }
399
400 static void deformVerts(
401                                          ModifierData *md, Object *ob, DerivedMesh *derivedData,
402          float (*vertexCos)[3], int numVerts, int useRenderParams, int isFinalCalc)
403 {
404         DerivedMesh *dm= derivedData;
405         WaveModifierData *wmd = (WaveModifierData *)md;
406
407         if(wmd->flag & MOD_WAVE_NORM)
408                 dm= get_cddm(md->scene, ob, NULL, dm, vertexCos);
409         else if(wmd->texture || wmd->defgrp_name[0])
410                 dm= get_dm(md->scene, ob, NULL, dm, NULL, 0);
411
412         waveModifier_do(wmd, md->scene, ob, dm, vertexCos, numVerts);
413
414         if(dm != derivedData)
415                 dm->release(dm);
416 }
417
418 static void deformVertsEM(
419                                            ModifierData *md, Object *ob, struct EditMesh *editData,
420            DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
421 {
422         DerivedMesh *dm= derivedData;
423         WaveModifierData *wmd = (WaveModifierData *)md;
424
425         if(wmd->flag & MOD_WAVE_NORM)
426                 dm= get_cddm(md->scene, ob, editData, dm, vertexCos);
427         else if(wmd->texture || wmd->defgrp_name[0])
428                 dm= get_dm(md->scene, ob, editData, dm, NULL, 0);
429
430         waveModifier_do(wmd, md->scene, ob, dm, vertexCos, numVerts);
431
432         if(dm != derivedData)
433                 dm->release(dm);
434 }
435
436
437 ModifierTypeInfo modifierType_Wave = {
438         /* name */              "Wave",
439         /* structName */        "WaveModifierData",
440         /* structSize */        sizeof(WaveModifierData),
441         /* type */              eModifierTypeType_OnlyDeform,
442         /* flags */             eModifierTypeFlag_AcceptsCVs
443                                                         | eModifierTypeFlag_SupportsEditmode,
444         /* copyData */          copyData,
445         /* deformVerts */       deformVerts,
446         /* deformVertsEM */     deformVertsEM,
447         /* deformMatricesEM */  0,
448         /* applyModifier */     0,
449         /* applyModifierEM */   0,
450         /* initData */          initData,
451         /* requiredDataMask */  requiredDataMask,
452         /* freeData */          0,
453         /* isDisabled */        0,
454         /* updateDepgraph */    updateDepgraph,
455         /* dependsOnTime */     dependsOnTime,
456         /* foreachObjectLink */ foreachObjectLink,
457         /* foreachIDLink */     foreachIDLink,
458 };