2 * ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
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.
18 * The Original Code is Copyright (C) Blender Foundation
19 * All rights reserved.
21 * The Original Code is: all of this file.
23 * Contributor(s): Matt Ebb
25 * ***** END GPL LICENSE BLOCK *****
28 #include "MEM_guardedalloc.h"
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"
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"
42 #include "BLI_blenlib.h"
44 #include "BLI_math_inline.h"
45 #include "BLI_utildefines.h"
46 #include "BLI_string.h"
51 static void init_cache_data(Object *ob, struct OceanModifierData *omd)
53 const char *relbase= modifier_path_relbase(ob);
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);
60 static void clear_cache_data(struct OceanModifierData *omd)
62 BKE_free_ocean_cache(omd->oceancache);
63 omd->oceancache = NULL;
67 /* keep in sync with init_ocean_modifier_bake(), object_modifier.c */
68 static void init_ocean_modifier(struct OceanModifierData *omd)
70 int do_heightfield, do_chop, do_normals, do_jacobian;
72 if (!omd || !omd->ocean) return;
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);
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,
87 static void simulate_ocean_modifier(struct OceanModifierData *omd)
89 if (!omd || !omd->ocean) return;
91 BKE_simulate_ocean(omd->ocean, omd->time, omd->wave_scale, omd->chop_amount);
93 #endif /* WITH_OCEANSIM */
99 static void initData(ModifierData *md)
102 OceanModifierData *omd = (OceanModifierData*) md;
105 omd->spatial_size = 50;
107 omd->wave_alignment = 0.0;
108 omd->wind_velocity = 30.0;
111 omd->smallest_wave = 0.01;
112 omd->wave_direction= 0.0;
115 omd->wave_scale = 1.0;
117 omd->chop_amount = 1.0;
119 omd->foam_coverage = 0.0;
130 modifier_path_init(omd->cachepath, sizeof(omd->cachepath), "cache_ocean");
135 omd->oceancache = NULL;
136 omd->foam_fade = 0.98;
137 omd->foamlayername[0] = '\0'; /* layer name empty by default */
139 omd->ocean = BKE_add_ocean();
140 init_ocean_modifier(omd);
141 simulate_ocean_modifier(omd);
142 #else // WITH_OCEANSIM
145 #endif // WITH_OCEANSIM
148 static void freeData(ModifierData *md)
151 OceanModifierData *omd = (OceanModifierData*) md;
153 BKE_free_ocean(omd->ocean);
155 BKE_free_ocean_cache(omd->oceancache);
156 #else // WITH_OCEANSIM
159 #endif // WITH_OCEANSIM
162 static void copyData(ModifierData *md, ModifierData *target)
165 OceanModifierData *omd = (OceanModifierData*) md;
166 OceanModifierData *tomd = (OceanModifierData*) target;
168 tomd->resolution = omd->resolution;
169 tomd->spatial_size = omd->spatial_size;
171 tomd->wind_velocity = omd->wind_velocity;
173 tomd->damp = omd->damp;
174 tomd->smallest_wave = omd->smallest_wave;
175 tomd->depth = omd->depth;
177 tomd->wave_alignment = omd->wave_alignment;
178 tomd->wave_direction = omd->wave_direction;
179 tomd->wave_scale = omd->wave_scale;
181 tomd->chop_amount = omd->chop_amount;
182 tomd->foam_coverage = omd->foam_coverage;
183 tomd->time = omd->time;
185 tomd->seed = omd->seed;
186 tomd->flag = omd->flag;
191 tomd->size = omd->size;
192 tomd->repeat_x = omd->repeat_x;
193 tomd->repeat_y = omd->repeat_y;
195 /* XXX todo: copy cache runtime too */
197 tomd->bakestart = omd->bakestart;
198 tomd->bakeend = omd->bakeend;
199 tomd->oceancache = NULL;
201 tomd->ocean = BKE_add_ocean();
202 init_ocean_modifier(tomd);
203 simulate_ocean_modifier(tomd);
204 #else // WITH_OCEANSIM
208 #endif // WITH_OCEANSIM
212 static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
214 OceanModifierData *omd = (OceanModifierData *)md;
215 CustomDataMask dataMask = 0;
217 if (omd->flag & MOD_OCEAN_GENERATE_FOAM)
218 dataMask |= CD_MASK_MCOL;
222 #else // WITH_OCEANSIM
223 static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
229 #endif // WITH_OCEANSIM
232 static void dm_get_bounds(DerivedMesh *dm, float *sx, float *sy, float *ox, float *oy)
234 /* get bounding box of underlying dm */
235 int v, totvert=dm->getNumVerts(dm);
236 float min[3], max[3], delta[3];
238 MVert *mvert = dm->getVertDataArray(dm,0);
240 copy_v3_v3(min, mvert->co);
241 copy_v3_v3(max, mvert->co);
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]);
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]);
253 sub_v3_v3v3(delta, max, min);
266 #define OMP_MIN_RES 18
267 static DerivedMesh *generate_ocean_geometry(OceanModifierData *omd)
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;
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;
285 const int num_faces = res_x * res_y;
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;
299 result = CDDM_new(num_verts, num_edges, num_faces);
301 mv = CDDM_get_verts(result);
302 mf = CDDM_get_faces(result);
303 origindex= result->getFaceDataArray(result, CD_ORIGINDEX);
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);
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;
324 mf[fi].v3 = vi + 1 + res_x+1;
325 mf[fi].v4 = vi + res_x+1;
327 mf[fi].flag |= ME_SMOOTH;
329 /* generated geometry does not map to original faces */
330 origindex[fi] = ORIGINDEX_NONE;
334 CDDM_calc_edges(result);
337 cdlayer= CustomData_number_of_layers(&result->faceData, CD_MTFACE);
338 if(cdlayer >= MAX_MTFACE)
340 CustomData_add_layer(&result->faceData, CD_MTFACE, CD_CALLOC, NULL, num_faces);
341 tf = CustomData_get_layer(&result->faceData, CD_MTFACE);
345 #pragma omp parallel for private(x, y) if (rx > OMP_MIN_RES)
346 for (y=0; y < res_y; y++) {
347 for (x=0; x < res_x; x++) {
348 const int i = y*res_x + x;
349 tf[i].uv[0][0] = x * ix;
350 tf[i].uv[0][1] = y * iy;
352 tf[i].uv[1][0] = (x+1) * ix;
353 tf[i].uv[1][1] = y * iy;
355 tf[i].uv[2][0] = (x+1) * ix;
356 tf[i].uv[2][1] = (y+1) * iy;
358 tf[i].uv[3][0] = x * ix;
359 tf[i].uv[3][1] = (y+1) * iy;
366 static DerivedMesh *doOcean(ModifierData *md, Object *ob,
367 DerivedMesh *derivedData,
368 int UNUSED(useRenderParams))
370 OceanModifierData *omd = (OceanModifierData*) md;
372 DerivedMesh *dm=NULL;
384 /* use cached & inverted value for speed
385 * expanded this would read...
387 * (axis / (omd->size * omd->spatial_size)) + 0.5f) */
388 #define OCEAN_CO(_size_co_inv, _v) ((_v * _size_co_inv) + 0.5f)
390 const float size_co_inv= 1.0f / (omd->size * omd->spatial_size);
392 /* update modifier */
393 if (omd->refresh & MOD_OCEAN_REFRESH_ADD)
394 omd->ocean = BKE_add_ocean();
395 if (omd->refresh & MOD_OCEAN_REFRESH_RESET)
396 init_ocean_modifier(omd);
397 if (omd->refresh & MOD_OCEAN_REFRESH_CLEAR_CACHE)
398 clear_cache_data(omd);
402 /* do ocean simulation */
403 if (omd->cached == TRUE) {
404 if (!omd->oceancache) init_cache_data(ob, omd);
405 BKE_simulate_ocean_cache(omd->oceancache, md->scene->r.cfra);
408 simulate_ocean_modifier(omd);
411 if (omd->geometry_mode == MOD_OCEAN_GEOM_GENERATE)
412 dm = generate_ocean_geometry(omd);
413 else if (omd->geometry_mode == MOD_OCEAN_GEOM_DISPLACE) {
414 dm = CDDM_copy(derivedData);
417 cfra = md->scene->r.cfra;
418 CLAMP(cfra, omd->bakestart, omd->bakeend);
419 cfra -= omd->bakestart; // shift to 0 based
421 num_verts = dm->getNumVerts(dm);
422 num_faces = dm->getNumFaces(dm);
424 mverts = dm->getVertArray(dm);
426 /* add vcols before displacement - allows lookup based on position */
428 if (omd->flag & MOD_OCEAN_GENERATE_FOAM) {
429 int cdlayer= CustomData_number_of_layers(&dm->faceData, CD_MCOL);
431 if(cdlayer < MAX_MCOL) {
432 MFace *mfaces= dm->getFaceArray(dm);
438 CustomData_add_layer_named(&dm->faceData, CD_MCOL, CD_CALLOC, NULL, num_faces, omd->foamlayername);
440 mcols = dm->getFaceDataArray(dm, CD_MCOL);
442 for (i = 0, mf= mfaces; i < num_faces; i++, mf++) {
445 const float *co= mverts[*(&mf->v1 + j)].co;
446 const float u = OCEAN_CO(size_co_inv, co[0]);
447 const float v = OCEAN_CO(size_co_inv, co[1]);
449 if (omd->oceancache && omd->cached==TRUE) {
450 BKE_ocean_cache_eval_uv(omd->oceancache, &ocr, cfra, u, v);
452 CLAMP(foam, 0.0f, 1.0f);
455 BKE_ocean_eval_uv(omd->ocean, &ocr, u, v);
456 foam = BKE_ocean_jminus_to_foam(ocr.Jminus, omd->foam_coverage);
460 mc->r = mc->g = mc->b = (char)(foam * 255);
461 /* mc->a = 255; */ /* no need to set */
468 /* displace the geometry */
470 //#pragma omp parallel for private(i, ocr) if (omd->resolution > OMP_MIN_RES)
471 for (i=0, mv= mverts; i< num_verts; i++, mv++) {
472 const float u = OCEAN_CO(size_co_inv, mv->co[0]);
473 const float v = OCEAN_CO(size_co_inv, mv->co[1]);
475 if (omd->oceancache && omd->cached==TRUE)
476 BKE_ocean_cache_eval_uv(omd->oceancache, &ocr, cfra, u, v);
478 BKE_ocean_eval_uv(omd->ocean, &ocr, u, v);
480 mv->co[2] += ocr.disp[1];
482 if (omd->chop_amount > 0.0f) {
483 mv->co[0] += ocr.disp[0];
484 mv->co[1] += ocr.disp[2];
492 #else // WITH_OCEANSIM
493 static DerivedMesh *doOcean(ModifierData *md, Object *UNUSED(ob),
494 DerivedMesh *derivedData,
495 int UNUSED(useRenderParams))
501 #endif // WITH_OCEANSIM
503 static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
504 DerivedMesh *derivedData,
505 int UNUSED(useRenderParams),
506 int UNUSED(isFinalCalc))
510 result = doOcean(md, ob, derivedData, 0);
512 if(result != derivedData)
513 CDDM_calc_normals(result);
518 static DerivedMesh *applyModifierEM(ModifierData *md, Object *ob,
519 struct BMEditMesh *UNUSED(editData),
520 DerivedMesh *derivedData)
522 return applyModifier(md, ob, derivedData, 0, 1);
527 ModifierTypeInfo modifierType_Ocean = {
529 /* structName */ "OceanModifierData",
530 /* structSize */ sizeof(OceanModifierData),
531 /* type */ eModifierTypeType_Constructive,
532 /* flags */ eModifierTypeFlag_AcceptsMesh
533 | eModifierTypeFlag_SupportsEditmode
534 | eModifierTypeFlag_EnableInEditmode,
536 /* copyData */ copyData,
537 /* deformMatrices */ NULL,
538 /* deformVerts */ NULL,
539 /* deformVertsEM */ NULL,
540 /* deformMatricesEM */ NULL,
541 /* applyModifier */ applyModifier,
542 /* applyModifierEM */ applyModifierEM,
543 /* initData */ initData,
544 /* requiredDataMask */ requiredDataMask,
545 /* freeData */ freeData,
546 /* isDisabled */ NULL,
547 /* updateDepgraph */ NULL,
548 /* dependsOnTime */ NULL,
549 /* dependsOnNormals */ NULL,
550 /* foreachObjectLink */ NULL,
551 /* foreachIDLink */ NULL,