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