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