Fix (unreported) bad copying of Ocean modifier.
[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 #if 0
164         OceanModifierData *omd = (OceanModifierData *) md;
165 #endif
166         OceanModifierData *tomd = (OceanModifierData *) target;
167
168         freeData(target);
169
170         modifier_copyData_generic(md, target);
171
172         tomd->refresh = 0;
173
174         /* XXX todo: copy cache runtime too */
175         tomd->cached = 0;
176         tomd->oceancache = NULL;
177
178         tomd->ocean = BKE_ocean_add();
179         init_ocean_modifier(tomd);
180         simulate_ocean_modifier(tomd);
181 #else /* WITH_OCEANSIM */
182         /* unused */
183         (void)md;
184         (void)target;
185 #endif /* WITH_OCEANSIM */
186 }
187
188 #ifdef WITH_OCEANSIM
189 static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
190 {
191         OceanModifierData *omd = (OceanModifierData *)md;
192         CustomDataMask dataMask = 0;
193
194         if (omd->flag & MOD_OCEAN_GENERATE_FOAM)
195                 dataMask |= CD_MASK_MCOL;
196
197         return dataMask;
198 }
199 #else /* WITH_OCEANSIM */
200 static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
201 {
202         /* unused */
203         (void)md;
204         return 0;
205 }
206 #endif /* WITH_OCEANSIM */
207
208 static bool dependsOnNormals(ModifierData *md)
209 {
210         OceanModifierData *omd = (OceanModifierData *)md;
211         return (omd->geometry_mode != MOD_OCEAN_GEOM_GENERATE);
212 }
213
214 #if 0
215 static void dm_get_bounds(DerivedMesh *dm, float *sx, float *sy, float *ox, float *oy)
216 {
217         /* get bounding box of underlying dm */
218         int v, totvert = dm->getNumVerts(dm);
219         float min[3], max[3], delta[3];
220
221         MVert *mvert = dm->getVertDataArray(dm, 0);
222
223         copy_v3_v3(min, mvert->co);
224         copy_v3_v3(max, mvert->co);
225
226         for (v = 1; v < totvert; v++, mvert++) {
227                 min[0] = min_ff(min[0], mvert->co[0]);
228                 min[1] = min_ff(min[1], mvert->co[1]);
229                 min[2] = min_ff(min[2], mvert->co[2]);
230
231                 max[0] = max_ff(max[0], mvert->co[0]);
232                 max[1] = max_ff(max[1], mvert->co[1]);
233                 max[2] = max_ff(max[2], mvert->co[2]);
234         }
235
236         sub_v3_v3v3(delta, max, min);
237
238         *sx = delta[0];
239         *sy = delta[1];
240
241         *ox = min[0];
242         *oy = min[1];
243 }
244 #endif
245
246 #ifdef WITH_OCEANSIM
247
248 typedef struct GenerateOceanGeometryData {
249         MVert *mverts;
250         MPoly *mpolys;
251         MLoop *mloops;
252         int *origindex;
253         MLoopUV *mloopuvs;
254
255         int res_x, res_y;
256         int rx, ry;
257         float ox, oy;
258         float sx, sy;
259         float ix, iy;
260 } GenerateOceanGeometryData;
261
262 static void generate_ocean_geometry_vertices(void *userdata, const int y)
263 {
264         GenerateOceanGeometryData *gogd = userdata;
265         int x;
266
267         for (x = 0; x <= gogd->res_x; x++) {
268                 const int i = y * (gogd->res_x + 1) + x;
269                 float *co = gogd->mverts[i].co;
270                 co[0] = gogd->ox + (x * gogd->sx);
271                 co[1] = gogd->oy + (y * gogd->sy);
272                 co[2] = 0.0f;
273         }
274 }
275
276 static void generate_ocean_geometry_polygons(void *userdata, const int y)
277 {
278         GenerateOceanGeometryData *gogd = userdata;
279         int x;
280
281         for (x = 0; x < gogd->res_x; x++) {
282                 const int fi = y * gogd->res_x + x;
283                 const int vi = y * (gogd->res_x + 1) + x;
284                 MPoly *mp = &gogd->mpolys[fi];
285                 MLoop *ml = &gogd->mloops[fi * 4];
286
287                 ml->v = vi;
288                 ml++;
289                 ml->v = vi + 1;
290                 ml++;
291                 ml->v = vi + 1 + gogd->res_x + 1;
292                 ml++;
293                 ml->v = vi + gogd->res_x + 1;
294                 ml++;
295
296                 mp->loopstart = fi * 4;
297                 mp->totloop = 4;
298
299                 mp->flag |= ME_SMOOTH;
300
301                 /* generated geometry does not map to original faces */
302                 gogd->origindex[fi] = ORIGINDEX_NONE;
303         }
304 }
305
306 static void generate_ocean_geometry_uvs(void *userdata, const int y)
307 {
308         GenerateOceanGeometryData *gogd = userdata;
309         int x;
310
311         for (x = 0; x < gogd->res_x; x++) {
312                 const int i = y * gogd->res_x + x;
313                 MLoopUV *luv = &gogd->mloopuvs[i * 4];
314
315                 luv->uv[0] = x * gogd->ix;
316                 luv->uv[1] = y * gogd->iy;
317                 luv++;
318
319                 luv->uv[0] = (x + 1) * gogd->ix;
320                 luv->uv[1] = y * gogd->iy;
321                 luv++;
322
323                 luv->uv[0] = (x + 1) * gogd->ix;
324                 luv->uv[1] = (y + 1) * gogd->iy;
325                 luv++;
326
327                 luv->uv[0] = x * gogd->ix;
328                 luv->uv[1] = (y + 1) * gogd->iy;
329                 luv++;
330         }
331 }
332
333 static DerivedMesh *generate_ocean_geometry(OceanModifierData *omd)
334 {
335         DerivedMesh *result;
336
337         GenerateOceanGeometryData gogd;
338
339         int num_verts;
340         int num_polys;
341
342         const bool use_threading = omd->resolution > 4;
343
344         gogd.rx = omd->resolution * omd->resolution;
345         gogd.ry = omd->resolution * omd->resolution;
346         gogd.res_x = gogd.rx * omd->repeat_x;
347         gogd.res_y = gogd.ry * omd->repeat_y;
348
349         num_verts = (gogd.res_x + 1) * (gogd.res_y + 1);
350         num_polys = gogd.res_x * gogd.res_y;
351
352         gogd.sx = omd->size * omd->spatial_size;
353         gogd.sy = omd->size * omd->spatial_size;
354         gogd.ox = -gogd.sx / 2.0f;
355         gogd.oy = -gogd.sy / 2.0f;
356
357         gogd.sx /= gogd.rx;
358         gogd.sy /= gogd.ry;
359
360         result = CDDM_new(num_verts, 0, 0, num_polys * 4, num_polys);
361
362         gogd.mverts = CDDM_get_verts(result);
363         gogd.mpolys = CDDM_get_polys(result);
364         gogd.mloops = CDDM_get_loops(result);
365
366         gogd.origindex = CustomData_get_layer(&result->polyData, CD_ORIGINDEX);
367
368         /* create vertices */
369         BLI_task_parallel_range(0, gogd.res_y + 1, &gogd, generate_ocean_geometry_vertices, use_threading);
370
371         /* create faces */
372         BLI_task_parallel_range(0, gogd.res_y, &gogd, generate_ocean_geometry_polygons, use_threading);
373
374         CDDM_calc_edges(result);
375
376         /* add uvs */
377         if (CustomData_number_of_layers(&result->loopData, CD_MLOOPUV) < MAX_MTFACE) {
378                 gogd.mloopuvs = CustomData_add_layer(&result->loopData, CD_MLOOPUV, CD_CALLOC, NULL, num_polys * 4);
379                 CustomData_add_layer(&result->polyData, CD_MTEXPOLY, CD_CALLOC, NULL, num_polys);
380
381                 if (gogd.mloopuvs) { /* unlikely to fail */
382                         gogd.ix = 1.0 / gogd.rx;
383                         gogd.iy = 1.0 / gogd.ry;
384
385                         BLI_task_parallel_range(0, gogd.res_y, &gogd, generate_ocean_geometry_uvs, use_threading);
386                 }
387         }
388
389         result->dirty |= DM_DIRTY_NORMALS;
390
391         return result;
392 }
393
394 static DerivedMesh *doOcean(ModifierData *md, Object *ob,
395                             DerivedMesh *derivedData,
396                             int UNUSED(useRenderParams))
397 {
398         OceanModifierData *omd = (OceanModifierData *) md;
399
400         DerivedMesh *dm = NULL;
401         OceanResult ocr;
402
403         MVert *mverts;
404
405         int cfra;
406         int i, j;
407
408         /* use cached & inverted value for speed
409          * expanded this would read...
410          *
411          * (axis / (omd->size * omd->spatial_size)) + 0.5f) */
412 #define OCEAN_CO(_size_co_inv, _v) ((_v * _size_co_inv) + 0.5f)
413
414         const float size_co_inv = 1.0f / (omd->size * omd->spatial_size);
415
416         /* can happen in when size is small, avoid bad array lookups later and quit now */
417         if (!isfinite(size_co_inv)) {
418                 return derivedData;
419         }
420
421         /* update modifier */
422         if (omd->refresh & MOD_OCEAN_REFRESH_ADD) {
423                 omd->ocean = BKE_ocean_add();
424         }
425         if (omd->refresh & MOD_OCEAN_REFRESH_RESET) {
426                 init_ocean_modifier(omd);
427         }
428         if (omd->refresh & MOD_OCEAN_REFRESH_CLEAR_CACHE) {
429                 clear_cache_data(omd);
430         }
431         omd->refresh = 0;
432
433         /* do ocean simulation */
434         if (omd->cached == true) {
435                 if (!omd->oceancache) {
436                         init_cache_data(ob, omd);
437                 }
438                 BKE_ocean_simulate_cache(omd->oceancache, md->scene->r.cfra);
439         }
440         else {
441                 simulate_ocean_modifier(omd);
442         }
443
444         if (omd->geometry_mode == MOD_OCEAN_GEOM_GENERATE) {
445                 dm = generate_ocean_geometry(omd);
446                 DM_ensure_normals(dm);
447         }
448         else if (omd->geometry_mode == MOD_OCEAN_GEOM_DISPLACE) {
449                 dm = CDDM_copy(derivedData);
450         }
451
452         cfra = md->scene->r.cfra;
453         CLAMP(cfra, omd->bakestart, omd->bakeend);
454         cfra -= omd->bakestart; /* shift to 0 based */
455
456         mverts = dm->getVertArray(dm);
457
458         /* add vcols before displacement - allows lookup based on position */
459
460         if (omd->flag & MOD_OCEAN_GENERATE_FOAM) {
461                 if (CustomData_number_of_layers(&dm->loopData, CD_MLOOPCOL) < MAX_MCOL) {
462                         const int num_polys = dm->getNumPolys(dm);
463                         const int num_loops = dm->getNumLoops(dm);
464                         MLoop *mloops = dm->getLoopArray(dm);
465                         MLoopCol *mloopcols = CustomData_add_layer_named(
466                                                   &dm->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, num_loops, omd->foamlayername);
467
468                         if (mloopcols) { /* unlikely to fail */
469                                 MPoly *mpolys = dm->getPolyArray(dm);
470                                 MPoly *mp;
471
472                                 for (i = 0, mp = mpolys; i < num_polys; i++, mp++) {
473                                         MLoop *ml = &mloops[mp->loopstart];
474                                         MLoopCol *mlcol = &mloopcols[mp->loopstart];
475
476                                         for (j = mp->totloop; j--; ml++, mlcol++) {
477                                                 const float *vco = mverts[ml->v].co;
478                                                 const float u = OCEAN_CO(size_co_inv, vco[0]);
479                                                 const float v = OCEAN_CO(size_co_inv, vco[1]);
480                                                 float foam;
481
482                                                 if (omd->oceancache && omd->cached == true) {
483                                                         BKE_ocean_cache_eval_uv(omd->oceancache, &ocr, cfra, u, v);
484                                                         foam = ocr.foam;
485                                                         CLAMP(foam, 0.0f, 1.0f);
486                                                 }
487                                                 else {
488                                                         BKE_ocean_eval_uv(omd->ocean, &ocr, u, v);
489                                                         foam = BKE_ocean_jminus_to_foam(ocr.Jminus, omd->foam_coverage);
490                                                 }
491
492                                                 mlcol->r = mlcol->g = mlcol->b = (char)(foam * 255);
493                                                 /* This needs to be set (render engine uses) */
494                                                 mlcol->a = 255;
495                                         }
496                                 }
497                         }
498                 }
499         }
500
501
502         /* displace the geometry */
503
504         /* Note: tried to parallelized that one and previous foam loop, but gives 20% slower results... odd. */
505         {
506                 const int num_verts = dm->getNumVerts(dm);
507
508                 for (i = 0; i < num_verts; i++) {
509                         float *vco = mverts[i].co;
510                         const float u = OCEAN_CO(size_co_inv, vco[0]);
511                         const float v = OCEAN_CO(size_co_inv, vco[1]);
512
513                         if (omd->oceancache && omd->cached == true) {
514                                 BKE_ocean_cache_eval_uv(omd->oceancache, &ocr, cfra, u, v);
515                         }
516                         else {
517                                 BKE_ocean_eval_uv(omd->ocean, &ocr, u, v);
518                         }
519
520                         vco[2] += ocr.disp[1];
521
522                         if (omd->chop_amount > 0.0f) {
523                                 vco[0] += ocr.disp[0];
524                                 vco[1] += ocr.disp[2];
525                         }
526                 }
527         }
528
529 #undef OCEAN_CO
530
531         return dm;
532 }
533 #else  /* WITH_OCEANSIM */
534 static DerivedMesh *doOcean(ModifierData *md, Object *UNUSED(ob),
535                             DerivedMesh *derivedData,
536                             int UNUSED(useRenderParams))
537 {
538         /* unused */
539         (void)md;
540         return derivedData;
541 }
542 #endif /* WITH_OCEANSIM */
543
544 static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
545                                   DerivedMesh *derivedData,
546                                   ModifierApplyFlag UNUSED(flag))
547 {
548         DerivedMesh *result;
549
550         result = doOcean(md, ob, derivedData, 0);
551
552         if (result != derivedData)
553                 result->dirty |= DM_DIRTY_NORMALS;
554
555         return result;
556 }
557
558
559 ModifierTypeInfo modifierType_Ocean = {
560         /* name */              "Ocean",
561         /* structName */        "OceanModifierData",
562         /* structSize */        sizeof(OceanModifierData),
563         /* type */              eModifierTypeType_Constructive,
564         /* flags */             eModifierTypeFlag_AcceptsMesh |
565                                 eModifierTypeFlag_SupportsEditmode |
566                                 eModifierTypeFlag_EnableInEditmode,
567
568         /* copyData */          copyData,
569         /* deformMatrices */    NULL,
570         /* deformVerts */       NULL,
571         /* deformVertsEM */     NULL,
572         /* deformMatricesEM */  NULL,
573         /* applyModifier */     applyModifier,
574         /* applyModifierEM */   NULL,
575         /* initData */          initData,
576         /* requiredDataMask */  requiredDataMask,
577         /* freeData */          freeData,
578         /* isDisabled */        NULL,
579         /* updateDepgraph */    NULL,
580         /* updateDepsgraph */   NULL,
581         /* dependsOnTime */     NULL,
582         /* dependsOnNormals */  dependsOnNormals,
583         /* foreachObjectLink */ NULL,
584         /* foreachIDLink */     NULL,
585         /* foreachTexLink */    NULL,
586 };