static void copyData(ModifierData *md, ModifierData *target) { #ifdef WITH_OCEANSIM OceanModifierData *omd = (OceanModifierData *) md; OceanModifierData *tomd = (OceanModifierData *) target; tomd->geometry_mode = omd->geometry_mode; tomd->resolution = omd->resolution; tomd->spatial_size = omd->spatial_size; tomd->wind_velocity = omd->wind_velocity; tomd->damp = omd->damp; tomd->smallest_wave = omd->smallest_wave; tomd->depth = omd->depth; tomd->wave_alignment = omd->wave_alignment; tomd->wave_direction = omd->wave_direction; tomd->wave_scale = omd->wave_scale; tomd->chop_amount = omd->chop_amount; tomd->foam_coverage = omd->foam_coverage; tomd->time = omd->time; tomd->seed = omd->seed; tomd->flag = omd->flag; tomd->refresh = 0; tomd->size = omd->size; tomd->repeat_x = omd->repeat_x; tomd->repeat_y = omd->repeat_y; /* XXX todo: copy cache runtime too */ tomd->cached = 0; tomd->bakestart = omd->bakestart; tomd->bakeend = omd->bakeend; tomd->oceancache = NULL; tomd->ocean = BKE_add_ocean(); init_ocean_modifier(tomd); simulate_ocean_modifier(tomd); #else /* WITH_OCEANSIM */ /* unused */ (void)md; (void)target; #endif /* WITH_OCEANSIM */ }
static void initData(ModifierData *md) { #ifdef WITH_OCEANSIM OceanModifierData *omd = (OceanModifierData *) md; omd->resolution = 7; omd->spatial_size = 50; omd->wave_alignment = 0.0; omd->wind_velocity = 30.0; omd->damp = 0.5; omd->smallest_wave = 0.01; omd->wave_direction = 0.0; omd->depth = 200.0; omd->wave_scale = 1.0; omd->chop_amount = 1.0; omd->foam_coverage = 0.0; omd->seed = 0; omd->time = 1.0; omd->refresh = 0; omd->size = 1.0; omd->repeat_x = 1; omd->repeat_y = 1; modifier_path_init(omd->cachepath, sizeof(omd->cachepath), "cache_ocean"); omd->cached = 0; omd->bakestart = 1; omd->bakeend = 250; omd->oceancache = NULL; omd->foam_fade = 0.98; omd->foamlayername[0] = '\0'; /* layer name empty by default */ omd->ocean = BKE_add_ocean(); init_ocean_modifier(omd); simulate_ocean_modifier(omd); #else /* WITH_OCEANSIM */ /* unused */ (void)md; #endif /* WITH_OCEANSIM */ }
static int ocean_bake_exec(bContext *C, wmOperator *op) { Object *ob = ED_object_active_context(C); OceanModifierData *omd = (OceanModifierData *)edit_modifier_property_get(op, ob, eModifierType_Ocean); Scene *scene = CTX_data_scene(C); OceanCache *och; struct Ocean *ocean; int f, cfra, i=0; int free= RNA_boolean_get(op->ptr, "free"); wmJob *steve; OceanBakeJob *oj; if (!omd) return OPERATOR_CANCELLED; if (free) { omd->refresh |= MOD_OCEAN_REFRESH_CLEAR_CACHE; DAG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob); return OPERATOR_FINISHED; } och = BKE_init_ocean_cache(omd->cachepath, modifier_path_relbase(ob), omd->bakestart, omd->bakeend, omd->wave_scale, omd->chop_amount, omd->foam_coverage, omd->foam_fade, omd->resolution); och->time = MEM_mallocN(och->duration*sizeof(float), "foam bake time"); cfra = scene->r.cfra; /* precalculate time variable before baking */ for (f=omd->bakestart; f<=omd->bakeend; f++) { /* from physics_fluid.c: * XXX: This can't be used due to an anim sys optimisation that ignores recalc object animation, * leaving it for the depgraph (this ignores object animation such as modifier properties though... :/ ) * --> BKE_animsys_evaluate_all_animation(G.main, eval_time); * This doesn't work with drivers: * --> BKE_animsys_evaluate_animdata(&fsDomain->id, fsDomain->adt, eval_time, ADT_RECALC_ALL); */ /* Modifying the global scene isn't nice, but we can do it in * this part of the process before a threaded job is created */ //scene->r.cfra = f; //ED_update_for_newframe(CTX_data_main(C), scene, CTX_wm_screen(C), 1); /* ok, this doesn't work with drivers, but is way faster. * let's use this for now and hope nobody wants to drive the time value... */ BKE_animsys_evaluate_animdata(scene, (ID *)ob, ob->adt, f, ADT_RECALC_ANIM); och->time[i] = omd->time; i++; } /* make a copy of ocean to use for baking - threadsafety */ ocean = BKE_add_ocean(); init_ocean_modifier_bake(ocean, omd); /* BKE_bake_ocean(ocean, och); omd->oceancache = och; omd->cached = TRUE; scene->r.cfra = cfra; DAG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob); */ /* job stuff */ scene->r.cfra = cfra; /* setup job */ steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Ocean Simulation", WM_JOB_PROGRESS); oj= MEM_callocN(sizeof(OceanBakeJob), "ocean bake job"); oj->ocean = ocean; oj->och = och; oj->omd = omd; WM_jobs_customdata(steve, oj, oceanbake_free); WM_jobs_timer(steve, 0.1, NC_OBJECT|ND_MODIFIER, NC_OBJECT|ND_MODIFIER); WM_jobs_callbacks(steve, oceanbake_startjob, NULL, NULL, oceanbake_endjob); WM_jobs_start(CTX_wm_manager(C), steve); return OPERATOR_FINISHED; }
static DerivedMesh *doOcean(ModifierData *md, Object *ob, DerivedMesh *derivedData, int UNUSED(useRenderParams)) { OceanModifierData *omd = (OceanModifierData *) md; DerivedMesh *dm = NULL; OceanResult ocr; MVert *mverts, *mv; MLoop *mloops; int i, j; int num_verts; int num_faces; int cfra; /* use cached & inverted value for speed * expanded this would read... * * (axis / (omd->size * omd->spatial_size)) + 0.5f) */ #define OCEAN_CO(_size_co_inv, _v) ((_v * _size_co_inv) + 0.5f) const float size_co_inv = 1.0f / (omd->size * omd->spatial_size); /* can happen in when size is small, avoid bad array lookups later and quit now */ if (!finite(size_co_inv)) { return derivedData; } /* update modifier */ if (omd->refresh & MOD_OCEAN_REFRESH_ADD) omd->ocean = BKE_add_ocean(); if (omd->refresh & MOD_OCEAN_REFRESH_RESET) init_ocean_modifier(omd); if (omd->refresh & MOD_OCEAN_REFRESH_CLEAR_CACHE) clear_cache_data(omd); omd->refresh = 0; /* do ocean simulation */ if (omd->cached == TRUE) { if (!omd->oceancache) init_cache_data(ob, omd); BKE_simulate_ocean_cache(omd->oceancache, md->scene->r.cfra); } else { simulate_ocean_modifier(omd); } if (omd->geometry_mode == MOD_OCEAN_GEOM_GENERATE) { dm = generate_ocean_geometry(omd); DM_ensure_normals(dm); } else if (omd->geometry_mode == MOD_OCEAN_GEOM_DISPLACE) { dm = CDDM_copy(derivedData); } cfra = md->scene->r.cfra; CLAMP(cfra, omd->bakestart, omd->bakeend); cfra -= omd->bakestart; /* shift to 0 based */ num_verts = dm->getNumVerts(dm); num_faces = dm->getNumPolys(dm); mverts = dm->getVertArray(dm); mloops = dm->getLoopArray(dm); /* add vcols before displacement - allows lookup based on position */ if (omd->flag & MOD_OCEAN_GENERATE_FOAM) { int cdlayer = CustomData_number_of_layers(&dm->loopData, CD_MLOOPCOL); if (cdlayer < MAX_MCOL) { MLoopCol *mloopcols = CustomData_add_layer_named(&dm->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, num_faces * 4, omd->foamlayername); if (mloopcols) { /* unlikely to fail */ MLoopCol *mlcol; MPoly *mpolys = dm->getPolyArray(dm); MPoly *mp; float foam; for (i = 0, mp = mpolys; i < num_faces; i++, mp++) { j = mp->totloop - 1; /* highly unlikely */ if (j <= 0) continue; do { const float *co = mverts[mloops[mp->loopstart + j].v].co; const float u = OCEAN_CO(size_co_inv, co[0]); const float v = OCEAN_CO(size_co_inv, co[1]); if (omd->oceancache && omd->cached == TRUE) { BKE_ocean_cache_eval_uv(omd->oceancache, &ocr, cfra, u, v); foam = ocr.foam; CLAMP(foam, 0.0f, 1.0f); } else { BKE_ocean_eval_uv(omd->ocean, &ocr, u, v); foam = BKE_ocean_jminus_to_foam(ocr.Jminus, omd->foam_coverage); } mlcol = &mloopcols[mp->loopstart + j]; mlcol->r = mlcol->g = mlcol->b = (char)(foam * 255); /* This needs to be set (render engine uses) */ mlcol->a = 255; } while (j--); } } } } /* displace the geometry */ /* #pragma omp parallel for private(i, ocr) if (omd->resolution > OMP_MIN_RES) */ for (i = 0, mv = mverts; i < num_verts; i++, mv++) { const float u = OCEAN_CO(size_co_inv, mv->co[0]); const float v = OCEAN_CO(size_co_inv, mv->co[1]); if (omd->oceancache && omd->cached == TRUE) BKE_ocean_cache_eval_uv(omd->oceancache, &ocr, cfra, u, v); else BKE_ocean_eval_uv(omd->ocean, &ocr, u, v); mv->co[2] += ocr.disp[1]; if (omd->chop_amount > 0.0f) { mv->co[0] += ocr.disp[0]; mv->co[1] += ocr.disp[2]; } } #undef OCEAN_CO return dm; }