a90a51e9ddc341ed4811e74e0a75ed8e16bca792
[blender.git] / source / blender / modifiers / intern / MOD_ocean.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) Blender Foundation
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): Matt Ebb
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/modifiers/intern/MOD_ocean.c
29  *  \ingroup modifiers
30  */
31
32 #include "DNA_customdata_types.h"
33 #include "DNA_object_types.h"
34 #include "DNA_meshdata_types.h"
35 #include "DNA_modifier_types.h"
36 #include "DNA_scene_types.h"
37
38 #include "BLI_math.h"
39 #include "BLI_math_inline.h"
40 #include "BLI_task.h"
41 #include "BLI_utildefines.h"
42
43 #include "BKE_cdderivedmesh.h"
44 #include "BKE_modifier.h"
45 #include "BKE_ocean.h"
46
47 #ifdef WITH_OCEANSIM
48 static void init_cache_data(Object *ob, struct OceanModifierData *omd)
49 {
50         const char *relbase = modifier_path_relbase(ob);
51
52         omd->oceancache = BKE_ocean_init_cache(omd->cachepath, relbase,
53                                                omd->bakestart, omd->bakeend, omd->wave_scale,
54                                                omd->chop_amount, omd->foam_coverage, omd->foam_fade, omd->resolution);
55 }
56
57 static void clear_cache_data(struct OceanModifierData *omd)
58 {
59         BKE_ocean_free_cache(omd->oceancache);
60         omd->oceancache = NULL;
61         omd->cached = false;
62 }
63
64 /* keep in sync with init_ocean_modifier_bake(), object_modifier.c */
65 static void init_ocean_modifier(struct OceanModifierData *omd)
66 {
67         int do_heightfield, do_chop, do_normals, do_jacobian;
68
69         if (!omd || !omd->ocean) return;
70
71         do_heightfield = true;
72         do_chop = (omd->chop_amount > 0);
73         do_normals = (omd->flag & MOD_OCEAN_GENERATE_NORMALS);
74         do_jacobian = (omd->flag & MOD_OCEAN_GENERATE_FOAM);
75
76         BKE_ocean_free_data(omd->ocean);
77         BKE_ocean_init(omd->ocean, omd->resolution * omd->resolution, omd->resolution * omd->resolution,
78                        omd->spatial_size, omd->spatial_size,
79                        omd->wind_velocity, omd->smallest_wave, 1.0, omd->wave_direction, omd->damp, omd->wave_alignment,
80                        omd->depth, omd->time,
81                        do_heightfield, do_chop, do_normals, do_jacobian,
82                        omd->seed);
83 }
84
85 static void simulate_ocean_modifier(struct OceanModifierData *omd)
86 {
87         if (!omd || !omd->ocean) return;
88
89         BKE_ocean_simulate(omd->ocean, omd->time, omd->wave_scale, omd->chop_amount);
90 }
91 #endif /* WITH_OCEANSIM */
92
93
94
95 /* Modifier Code */
96
97 static void initData(ModifierData *md)
98 {
99 #ifdef WITH_OCEANSIM
100         OceanModifierData *omd = (OceanModifierData *) md;
101
102         omd->resolution = 7;
103         omd->spatial_size = 50;
104
105         omd->wave_alignment = 0.0;
106         omd->wind_velocity = 30.0;
107
108         omd->damp = 0.5;
109         omd->smallest_wave = 0.01;
110         omd->wave_direction = 0.0;
111         omd->depth = 200.0;
112
113         omd->wave_scale = 1.0;
114
115         omd->chop_amount = 1.0;
116
117         omd->foam_coverage = 0.0;
118
119         omd->seed = 0;
120         omd->time = 1.0;
121
122         omd->refresh = 0;
123
124         omd->size = 1.0;
125         omd->repeat_x = 1;
126         omd->repeat_y = 1;
127
128         modifier_path_init(omd->cachepath, sizeof(omd->cachepath), "cache_ocean");
129
130         omd->cached = 0;
131         omd->bakestart = 1;
132         omd->bakeend = 250;
133         omd->oceancache = NULL;
134         omd->foam_fade = 0.98;
135         omd->foamlayername[0] = '\0';   /* layer name empty by default */
136
137         omd->ocean = BKE_ocean_add();
138         init_ocean_modifier(omd);
139         simulate_ocean_modifier(omd);
140 #else  /* WITH_OCEANSIM */
141            /* unused */
142         (void)md;
143 #endif /* WITH_OCEANSIM */
144 }
145
146 static void freeData(ModifierData *md)
147 {
148 #ifdef WITH_OCEANSIM
149         OceanModifierData *omd = (OceanModifierData *) md;
150
151         BKE_ocean_free(omd->ocean);
152         if (omd->oceancache)
153                 BKE_ocean_free_cache(omd->oceancache);
154 #else /* WITH_OCEANSIM */
155         /* unused */
156         (void)md;
157 #endif /* WITH_OCEANSIM */
158 }
159
160 static void copyData(ModifierData *md, ModifierData *target)
161 {
162 #ifdef WITH_OCEANSIM
163         OceanModifierData *omd = (OceanModifierData *) md;
164         OceanModifierData *tomd = (OceanModifierData *) target;
165
166         tomd->geometry_mode = omd->geometry_mode;
167         tomd->resolution = omd->resolution;
168         tomd->spatial_size = omd->spatial_size;
169
170         tomd->wind_velocity = omd->wind_velocity;
171
172         tomd->damp = omd->damp;
173         tomd->smallest_wave = omd->smallest_wave;
174         tomd->depth = omd->depth;
175
176         tomd->wave_alignment = omd->wave_alignment;
177         tomd->wave_direction = omd->wave_direction;
178         tomd->wave_scale = omd->wave_scale;
179
180         tomd->chop_amount = omd->chop_amount;
181         tomd->foam_coverage = omd->foam_coverage;
182         tomd->time = omd->time;
183
184         tomd->seed = omd->seed;
185         tomd->flag = omd->flag;
186
187         tomd->refresh = 0;
188
189         tomd->size = omd->size;
190         tomd->repeat_x = omd->repeat_x;
191         tomd->repeat_y = omd->repeat_y;
192
193         /* XXX todo: copy cache runtime too */
194         tomd->cached = 0;
195         tomd->bakestart = omd->bakestart;
196         tomd->bakeend = omd->bakeend;
197         tomd->oceancache = NULL;
198
199         tomd->ocean = BKE_ocean_add();
200         init_ocean_modifier(tomd);
201         simulate_ocean_modifier(tomd);
202 #else /* WITH_OCEANSIM */
203         /* unused */
204         (void)md;
205         (void)target;
206 #endif /* WITH_OCEANSIM */
207 }
208
209 #ifdef WITH_OCEANSIM
210 static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
211 {
212         OceanModifierData *omd = (OceanModifierData *)md;
213         CustomDataMask dataMask = 0;
214
215         if (omd->flag & MOD_OCEAN_GENERATE_FOAM)
216                 dataMask |= CD_MASK_MCOL;
217
218         return dataMask;
219 }
220 #else /* WITH_OCEANSIM */
221 static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
222 {
223         /* unused */
224         (void)md;
225         return 0;
226 }
227 #endif /* WITH_OCEANSIM */
228
229 static bool dependsOnNormals(ModifierData *md)
230 {
231         OceanModifierData *omd = (OceanModifierData *)md;
232         return (omd->geometry_mode != MOD_OCEAN_GEOM_GENERATE);
233 }
234
235 #if 0
236 static void dm_get_bounds(DerivedMesh *dm, float *sx, float *sy, float *ox, float *oy)
237 {
238         /* get bounding box of underlying dm */
239         int v, totvert = dm->getNumVerts(dm);
240         float min[3], max[3], delta[3];
241
242         MVert *mvert = dm->getVertDataArray(dm, 0);
243
244         copy_v3_v3(min, mvert->co);
245         copy_v3_v3(max, mvert->co);
246
247         for (v = 1; v < totvert; v++, mvert++) {
248                 min[0] = min_ff(min[0], mvert->co[0]);
249                 min[1] = min_ff(min[1], mvert->co[1]);
250                 min[2] = min_ff(min[2], mvert->co[2]);
251
252                 max[0] = max_ff(max[0], mvert->co[0]);
253                 max[1] = max_ff(max[1], mvert->co[1]);
254                 max[2] = max_ff(max[2], mvert->co[2]);
255         }
256
257         sub_v3_v3v3(delta, max, min);
258
259         *sx = delta[0];
260         *sy = delta[1];
261
262         *ox = min[0];
263         *oy = min[1];
264 }
265 #endif
266
267 #ifdef WITH_OCEANSIM
268
269 typedef struct GenerateOceanGeometryData {
270         MVert *mverts;
271         MPoly *mpolys;
272         MLoop *mloops;
273         int *origindex;
274         MLoopUV *mloopuvs;
275
276         int res_x, res_y;
277         int rx, ry;
278         float ox, oy;
279         float sx, sy;
280         float ix, iy;
281 } GenerateOceanGeometryData;
282
283 static void generate_ocean_geometry_vertices(void *userdata, const int y)
284 {
285         GenerateOceanGeometryData *gogd = userdata;
286         int x;
287
288         for (x = 0; x <= gogd->res_x; x++) {
289                 const int i = y * (gogd->res_x + 1) + x;
290                 float *co = gogd->mverts[i].co;
291                 co[0] = gogd->ox + (x * gogd->sx);
292                 co[1] = gogd->oy + (y * gogd->sy);
293                 co[2] = 0.0f;
294         }
295 }
296
297 static void generate_ocean_geometry_polygons(void *userdata, const int y)
298 {
299         GenerateOceanGeometryData *gogd = userdata;
300         int x;
301
302         for (x = 0; x < gogd->res_x; x++) {
303                 const int fi = y * gogd->res_x + x;
304                 const int vi = y * (gogd->res_x + 1) + x;
305                 MPoly *mp = &gogd->mpolys[fi];
306                 MLoop *ml = &gogd->mloops[fi * 4];
307
308                 ml->v = vi;
309                 ml++;
310                 ml->v = vi + 1;
311                 ml++;
312                 ml->v = vi + 1 + gogd->res_x + 1;
313                 ml++;
314                 ml->v = vi + gogd->res_x + 1;
315                 ml++;
316
317                 mp->loopstart = fi * 4;
318                 mp->totloop = 4;
319
320                 mp->flag |= ME_SMOOTH;
321
322                 /* generated geometry does not map to original faces */
323                 gogd->origindex[fi] = ORIGINDEX_NONE;
324         }
325 }
326
327 static void generate_ocean_geometry_uvs(void *userdata, const int y)
328 {
329         GenerateOceanGeometryData *gogd = userdata;
330         int x;
331
332         for (x = 0; x < gogd->res_x; x++) {
333                 const int i = y * gogd->res_x + x;
334                 MLoopUV *luv = &gogd->mloopuvs[i * 4];
335
336                 luv->uv[0] = x * gogd->ix;
337                 luv->uv[1] = y * gogd->iy;
338                 luv++;
339
340                 luv->uv[0] = (x + 1) * gogd->ix;
341                 luv->uv[1] = y * gogd->iy;
342                 luv++;
343
344                 luv->uv[0] = (x + 1) * gogd->ix;
345                 luv->uv[1] = (y + 1) * gogd->iy;
346                 luv++;
347
348                 luv->uv[0] = x * gogd->ix;
349                 luv->uv[1] = (y + 1) * gogd->iy;
350                 luv++;
351         }
352 }
353
354 static DerivedMesh *generate_ocean_geometry(OceanModifierData *omd)
355 {
356         DerivedMesh *result;
357
358         GenerateOceanGeometryData gogd;
359
360         int num_verts;
361         int num_polys;
362
363         const bool use_threading = omd->resolution > 4;
364
365         gogd.rx = omd->resolution * omd->resolution;
366         gogd.ry = omd->resolution * omd->resolution;
367         gogd.res_x = gogd.rx * omd->repeat_x;
368         gogd.res_y = gogd.ry * omd->repeat_y;
369
370         num_verts = (gogd.res_x + 1) * (gogd.res_y + 1);
371         num_polys = gogd.res_x * gogd.res_y;
372
373         gogd.sx = omd->size * omd->spatial_size;
374         gogd.sy = omd->size * omd->spatial_size;
375         gogd.ox = -gogd.sx / 2.0f;
376         gogd.oy = -gogd.sy / 2.0f;
377
378         gogd.sx /= gogd.rx;
379         gogd.sy /= gogd.ry;
380
381         result = CDDM_new(num_verts, 0, 0, num_polys * 4, num_polys);
382
383         gogd.mverts = CDDM_get_verts(result);
384         gogd.mpolys = CDDM_get_polys(result);
385         gogd.mloops = CDDM_get_loops(result);
386
387         gogd.origindex = CustomData_get_layer(&result->polyData, CD_ORIGINDEX);
388
389         /* create vertices */
390         BLI_task_parallel_range(0, gogd.res_y + 1, &gogd, generate_ocean_geometry_vertices, use_threading);
391
392         /* create faces */
393         BLI_task_parallel_range(0, gogd.res_y, &gogd, generate_ocean_geometry_polygons, use_threading);
394
395         CDDM_calc_edges(result);
396
397         /* add uvs */
398         if (CustomData_number_of_layers(&result->loopData, CD_MLOOPUV) < MAX_MTFACE) {
399                 gogd.mloopuvs = CustomData_add_layer(&result->loopData, CD_MLOOPUV, CD_CALLOC, NULL, num_polys * 4);
400                 CustomData_add_layer(&result->polyData, CD_MTEXPOLY, CD_CALLOC, NULL, num_polys);
401
402                 if (gogd.mloopuvs) { /* unlikely to fail */
403                         gogd.ix = 1.0 / gogd.rx;
404                         gogd.iy = 1.0 / gogd.ry;
405
406                         BLI_task_parallel_range(0, gogd.res_y, &gogd, generate_ocean_geometry_uvs, use_threading);
407                 }
408         }
409
410         result->dirty |= DM_DIRTY_NORMALS;
411
412         return result;
413 }
414
415 static DerivedMesh *doOcean(ModifierData *md, Object *ob,
416                             DerivedMesh *derivedData,
417                             int UNUSED(useRenderParams))
418 {
419         OceanModifierData *omd = (OceanModifierData *) md;
420
421         DerivedMesh *dm = NULL;
422         OceanResult ocr;
423
424         MVert *mverts;
425
426         int cfra;
427         int i, j;
428
429         /* use cached & inverted value for speed
430          * expanded this would read...
431          *
432          * (axis / (omd->size * omd->spatial_size)) + 0.5f) */
433 #define OCEAN_CO(_size_co_inv, _v) ((_v * _size_co_inv) + 0.5f)
434
435         const float size_co_inv = 1.0f / (omd->size * omd->spatial_size);
436
437         /* can happen in when size is small, avoid bad array lookups later and quit now */
438         if (!finite(size_co_inv)) {
439                 return derivedData;
440         }
441
442         /* update modifier */
443         if (omd->refresh & MOD_OCEAN_REFRESH_ADD) {
444                 omd->ocean = BKE_ocean_add();
445         }
446         if (omd->refresh & MOD_OCEAN_REFRESH_RESET) {
447                 init_ocean_modifier(omd);
448         }
449         if (omd->refresh & MOD_OCEAN_REFRESH_CLEAR_CACHE) {
450                 clear_cache_data(omd);
451         }
452         omd->refresh = 0;
453
454         /* do ocean simulation */
455         if (omd->cached == true) {
456                 if (!omd->oceancache) {
457                         init_cache_data(ob, omd);
458                 }
459                 BKE_ocean_simulate_cache(omd->oceancache, md->scene->r.cfra);
460         }
461         else {
462                 simulate_ocean_modifier(omd);
463         }
464
465         if (omd->geometry_mode == MOD_OCEAN_GEOM_GENERATE) {
466                 dm = generate_ocean_geometry(omd);
467                 DM_ensure_normals(dm);
468         }
469         else if (omd->geometry_mode == MOD_OCEAN_GEOM_DISPLACE) {
470                 dm = CDDM_copy(derivedData);
471         }
472
473         cfra = md->scene->r.cfra;
474         CLAMP(cfra, omd->bakestart, omd->bakeend);
475         cfra -= omd->bakestart; /* shift to 0 based */
476
477         mverts = dm->getVertArray(dm);
478
479         /* add vcols before displacement - allows lookup based on position */
480
481         if (omd->flag & MOD_OCEAN_GENERATE_FOAM) {
482                 if (CustomData_number_of_layers(&dm->loopData, CD_MLOOPCOL) < MAX_MCOL) {
483                         const int num_polys = dm->getNumPolys(dm);
484                         const int num_loops = dm->getNumLoops(dm);
485                         MLoop *mloops = dm->getLoopArray(dm);
486                         MLoopCol *mloopcols = CustomData_add_layer_named(
487                                                   &dm->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, num_loops, omd->foamlayername);
488
489                         if (mloopcols) { /* unlikely to fail */
490                                 MPoly *mpolys = dm->getPolyArray(dm);
491                                 MPoly *mp;
492
493                                 for (i = 0, mp = mpolys; i < num_polys; i++, mp++) {
494                                         MLoop *ml = &mloops[mp->loopstart];
495                                         MLoopCol *mlcol = &mloopcols[mp->loopstart];
496
497                                         for (j = mp->totloop; j--; ml++, mlcol++) {
498                                                 const float *vco = mverts[ml->v].co;
499                                                 const float u = OCEAN_CO(size_co_inv, vco[0]);
500                                                 const float v = OCEAN_CO(size_co_inv, vco[1]);
501                                                 float foam;
502
503                                                 if (omd->oceancache && omd->cached == true) {
504                                                         BKE_ocean_cache_eval_uv(omd->oceancache, &ocr, cfra, u, v);
505                                                         foam = ocr.foam;
506                                                         CLAMP(foam, 0.0f, 1.0f);
507                                                 }
508                                                 else {
509                                                         BKE_ocean_eval_uv(omd->ocean, &ocr, u, v);
510                                                         foam = BKE_ocean_jminus_to_foam(ocr.Jminus, omd->foam_coverage);
511                                                 }
512
513                                                 mlcol->r = mlcol->g = mlcol->b = (char)(foam * 255);
514                                                 /* This needs to be set (render engine uses) */
515                                                 mlcol->a = 255;
516                                         }
517                                 }
518                         }
519                 }
520         }
521
522
523         /* displace the geometry */
524
525         /* Note: tried to parallelized that one and previous foam loop, but gives 20% slower results... odd. */
526         {
527                 const int num_verts = dm->getNumVerts(dm);
528
529                 for (i = 0; i < num_verts; i++) {
530                         float *vco = mverts[i].co;
531                         const float u = OCEAN_CO(size_co_inv, vco[0]);
532                         const float v = OCEAN_CO(size_co_inv, vco[1]);
533
534                         if (omd->oceancache && omd->cached == true) {
535                                 BKE_ocean_cache_eval_uv(omd->oceancache, &ocr, cfra, u, v);
536                         }
537                         else {
538                                 BKE_ocean_eval_uv(omd->ocean, &ocr, u, v);
539                         }
540
541                         vco[2] += ocr.disp[1];
542
543                         if (omd->chop_amount > 0.0f) {
544                                 vco[0] += ocr.disp[0];
545                                 vco[1] += ocr.disp[2];
546                         }
547                 }
548         }
549
550 #undef OCEAN_CO
551
552         return dm;
553 }
554 #else  /* WITH_OCEANSIM */
555 static DerivedMesh *doOcean(ModifierData *md, Object *UNUSED(ob),
556                             DerivedMesh *derivedData,
557                             int UNUSED(useRenderParams))
558 {
559         /* unused */
560         (void)md;
561         return derivedData;
562 }
563 #endif /* WITH_OCEANSIM */
564
565 static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
566                                   DerivedMesh *derivedData,
567                                   ModifierApplyFlag UNUSED(flag))
568 {
569         DerivedMesh *result;
570
571         result = doOcean(md, ob, derivedData, 0);
572
573         if (result != derivedData)
574                 result->dirty |= DM_DIRTY_NORMALS;
575
576         return result;
577 }
578
579
580 ModifierTypeInfo modifierType_Ocean = {
581         /* name */              "Ocean",
582         /* structName */        "OceanModifierData",
583         /* structSize */        sizeof(OceanModifierData),
584         /* type */              eModifierTypeType_Constructive,
585         /* flags */             eModifierTypeFlag_AcceptsMesh |
586                                 eModifierTypeFlag_SupportsEditmode |
587                                 eModifierTypeFlag_EnableInEditmode,
588
589         /* copyData */          copyData,
590         /* deformMatrices */    NULL,
591         /* deformVerts */       NULL,
592         /* deformVertsEM */     NULL,
593         /* deformMatricesEM */  NULL,
594         /* applyModifier */     applyModifier,
595         /* applyModifierEM */   NULL,
596         /* initData */          initData,
597         /* requiredDataMask */  requiredDataMask,
598         /* freeData */          freeData,
599         /* isDisabled */        NULL,
600         /* updateDepgraph */    NULL,
601         /* updateDepsgraph */   NULL,
602         /* dependsOnTime */     NULL,
603         /* dependsOnNormals */  dependsOnNormals,
604         /* foreachObjectLink */ NULL,
605         /* foreachIDLink */     NULL,
606         /* foreachTexLink */    NULL,
607 };