diff options
author | Campbell Barton <ideasman42@gmail.com> | 2019-04-17 07:17:24 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2019-04-17 07:21:24 +0300 |
commit | e12c08e8d170b7ca40f204a5b0423c23a9fbc2c1 (patch) | |
tree | 8cf3453d12edb177a218ef8009357518ec6cab6a /source/blender/blenkernel/intern/smoke.c | |
parent | b3dabc200a4b0399ec6b81f2ff2730d07b44fcaa (diff) |
ClangFormat: apply to source, most of intern
Apply clang format as proposed in T53211.
For details on usage and instructions for migrating branches
without conflicts, see:
https://wiki.blender.org/wiki/Tools/ClangFormat
Diffstat (limited to 'source/blender/blenkernel/intern/smoke.c')
-rw-r--r-- | source/blender/blenkernel/intern/smoke.c | 6053 |
1 files changed, 3219 insertions, 2834 deletions
diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c index 122bb5a19c5..23cdf802c81 100644 --- a/source/blender/blenkernel/intern/smoke.c +++ b/source/blender/blenkernel/intern/smoke.c @@ -21,7 +21,6 @@ * \ingroup bke */ - /* Part of the code copied from elbeem fluid library, copyright by Nils Thuerey */ #include "MEM_guardedalloc.h" @@ -89,11 +88,11 @@ #ifdef WITH_SMOKE -#include "smoke_API.h" +# include "smoke_API.h" -#include "BLI_task.h" -#include "BLI_kdtree.h" -#include "BLI_voxel.h" +# include "BLI_task.h" +# include "BLI_kdtree.h" +# include "BLI_voxel.h" static ThreadMutex object_update_lock = BLI_MUTEX_INITIALIZER; @@ -103,26 +102,66 @@ struct Scene; struct SmokeModifierData; // timestep default value for nice appearance 0.1f -#define DT_DEFAULT 0.1f +# define DT_DEFAULT 0.1f -#define ADD_IF_LOWER_POS(a, b) (min_ff((a) + (b), max_ff((a), (b)))) -#define ADD_IF_LOWER_NEG(a, b) (max_ff((a) + (b), min_ff((a), (b)))) -#define ADD_IF_LOWER(a, b) (((b) > 0) ? ADD_IF_LOWER_POS((a), (b)) : ADD_IF_LOWER_NEG((a), (b))) +# define ADD_IF_LOWER_POS(a, b) (min_ff((a) + (b), max_ff((a), (b)))) +# define ADD_IF_LOWER_NEG(a, b) (max_ff((a) + (b), min_ff((a), (b)))) +# define ADD_IF_LOWER(a, b) (((b) > 0) ? ADD_IF_LOWER_POS((a), (b)) : ADD_IF_LOWER_NEG((a), (b))) #else /* WITH_SMOKE */ /* Stubs to use when smoke is disabled */ -struct WTURBULENCE *smoke_turbulence_init(int *UNUSED(res), int UNUSED(amplify), int UNUSED(noisetype), const char *UNUSED(noisefile_path), int UNUSED(use_fire), int UNUSED(use_colors)) { return NULL; } +struct WTURBULENCE *smoke_turbulence_init(int *UNUSED(res), + int UNUSED(amplify), + int UNUSED(noisetype), + const char *UNUSED(noisefile_path), + int UNUSED(use_fire), + int UNUSED(use_colors)) +{ + return NULL; +} //struct FLUID_3D *smoke_init(int *UNUSED(res), float *UNUSED(dx), float *UNUSED(dtdef), int UNUSED(use_heat), int UNUSED(use_fire), int UNUSED(use_colors)) { return NULL; } -void smoke_free(struct FLUID_3D *UNUSED(fluid)) {} -float *smoke_get_density(struct FLUID_3D *UNUSED(fluid)) { return NULL; } -void smoke_turbulence_free(struct WTURBULENCE *UNUSED(wt)) {} -void smoke_initWaveletBlenderRNA(struct WTURBULENCE *UNUSED(wt), float *UNUSED(strength)) {} -void smoke_initBlenderRNA(struct FLUID_3D *UNUSED(fluid), float *UNUSED(alpha), float *UNUSED(beta), float *UNUSED(dt_factor), float *UNUSED(vorticity), - int *UNUSED(border_colli), float *UNUSED(burning_rate), float *UNUSED(flame_smoke), float *UNUSED(flame_smoke_color), - float *UNUSED(flame_vorticity), float *UNUSED(flame_ignition_temp), float *UNUSED(flame_max_temp)) {} -struct Mesh *smokeModifier_do(SmokeModifierData *UNUSED(smd), Depsgraph *UNUSED(depsgraph), Scene *UNUSED(scene), Object *UNUSED(ob), Mesh *UNUSED(me)) { return NULL; } -float BKE_smoke_get_velocity_at(struct Object *UNUSED(ob), float UNUSED(position[3]), float UNUSED(velocity[3])) { return 0.0f; } +void smoke_free(struct FLUID_3D *UNUSED(fluid)) +{ +} +float *smoke_get_density(struct FLUID_3D *UNUSED(fluid)) +{ + return NULL; +} +void smoke_turbulence_free(struct WTURBULENCE *UNUSED(wt)) +{ +} +void smoke_initWaveletBlenderRNA(struct WTURBULENCE *UNUSED(wt), float *UNUSED(strength)) +{ +} +void smoke_initBlenderRNA(struct FLUID_3D *UNUSED(fluid), + float *UNUSED(alpha), + float *UNUSED(beta), + float *UNUSED(dt_factor), + float *UNUSED(vorticity), + int *UNUSED(border_colli), + float *UNUSED(burning_rate), + float *UNUSED(flame_smoke), + float *UNUSED(flame_smoke_color), + float *UNUSED(flame_vorticity), + float *UNUSED(flame_ignition_temp), + float *UNUSED(flame_max_temp)) +{ +} +struct Mesh *smokeModifier_do(SmokeModifierData *UNUSED(smd), + Depsgraph *UNUSED(depsgraph), + Scene *UNUSED(scene), + Object *UNUSED(ob), + Mesh *UNUSED(me)) +{ + return NULL; +} +float BKE_smoke_get_velocity_at(struct Object *UNUSED(ob), + float UNUSED(position[3]), + float UNUSED(velocity[3])) +{ + return 0.0f; +} #endif /* WITH_SMOKE */ @@ -130,613 +169,616 @@ float BKE_smoke_get_velocity_at(struct Object *UNUSED(ob), float UNUSED(position void BKE_smoke_reallocate_fluid(SmokeDomainSettings *sds, float dx, int res[3], int free_old) { - int use_heat = (sds->active_fields & SM_ACTIVE_HEAT); - int use_fire = (sds->active_fields & SM_ACTIVE_FIRE); - int use_colors = (sds->active_fields & SM_ACTIVE_COLORS); - - if (free_old && sds->fluid) - smoke_free(sds->fluid); - if (!min_iii(res[0], res[1], res[2])) { - sds->fluid = NULL; - return; - } - sds->fluid = smoke_init(res, dx, DT_DEFAULT, use_heat, use_fire, use_colors); - smoke_initBlenderRNA(sds->fluid, &(sds->alpha), &(sds->beta), &(sds->time_scale), &(sds->vorticity), &(sds->border_collisions), - &(sds->burning_rate), &(sds->flame_smoke), sds->flame_smoke_color, &(sds->flame_vorticity), &(sds->flame_ignition), &(sds->flame_max_temp)); - - /* reallocate shadow buffer */ - if (sds->shadow) - MEM_freeN(sds->shadow); - sds->shadow = MEM_callocN(sizeof(float) * res[0] * res[1] * res[2], "SmokeDomainShadow"); + int use_heat = (sds->active_fields & SM_ACTIVE_HEAT); + int use_fire = (sds->active_fields & SM_ACTIVE_FIRE); + int use_colors = (sds->active_fields & SM_ACTIVE_COLORS); + + if (free_old && sds->fluid) + smoke_free(sds->fluid); + if (!min_iii(res[0], res[1], res[2])) { + sds->fluid = NULL; + return; + } + sds->fluid = smoke_init(res, dx, DT_DEFAULT, use_heat, use_fire, use_colors); + smoke_initBlenderRNA(sds->fluid, + &(sds->alpha), + &(sds->beta), + &(sds->time_scale), + &(sds->vorticity), + &(sds->border_collisions), + &(sds->burning_rate), + &(sds->flame_smoke), + sds->flame_smoke_color, + &(sds->flame_vorticity), + &(sds->flame_ignition), + &(sds->flame_max_temp)); + + /* reallocate shadow buffer */ + if (sds->shadow) + MEM_freeN(sds->shadow); + sds->shadow = MEM_callocN(sizeof(float) * res[0] * res[1] * res[2], "SmokeDomainShadow"); } -void BKE_smoke_reallocate_highres_fluid(SmokeDomainSettings *sds, float dx, int res[3], int free_old) +void BKE_smoke_reallocate_highres_fluid(SmokeDomainSettings *sds, + float dx, + int res[3], + int free_old) { - int use_fire = (sds->active_fields & (SM_ACTIVE_HEAT | SM_ACTIVE_FIRE)); - int use_colors = (sds->active_fields & SM_ACTIVE_COLORS); + int use_fire = (sds->active_fields & (SM_ACTIVE_HEAT | SM_ACTIVE_FIRE)); + int use_colors = (sds->active_fields & SM_ACTIVE_COLORS); - if (free_old && sds->wt) - smoke_turbulence_free(sds->wt); - if (!min_iii(res[0], res[1], res[2])) { - sds->wt = NULL; - return; - } + if (free_old && sds->wt) + smoke_turbulence_free(sds->wt); + if (!min_iii(res[0], res[1], res[2])) { + sds->wt = NULL; + return; + } - /* smoke_turbulence_init uses non-threadsafe functions from fftw3 lib (like fftw_plan & co). */ - BLI_thread_lock(LOCK_FFTW); + /* smoke_turbulence_init uses non-threadsafe functions from fftw3 lib (like fftw_plan & co). */ + BLI_thread_lock(LOCK_FFTW); - sds->wt = smoke_turbulence_init(res, sds->amplify + 1, sds->noise, BKE_tempdir_session(), use_fire, use_colors); + sds->wt = smoke_turbulence_init( + res, sds->amplify + 1, sds->noise, BKE_tempdir_session(), use_fire, use_colors); - BLI_thread_unlock(LOCK_FFTW); + BLI_thread_unlock(LOCK_FFTW); - sds->res_wt[0] = res[0] * (sds->amplify + 1); - sds->res_wt[1] = res[1] * (sds->amplify + 1); - sds->res_wt[2] = res[2] * (sds->amplify + 1); - sds->dx_wt = dx / (sds->amplify + 1); - smoke_initWaveletBlenderRNA(sds->wt, &(sds->strength)); + sds->res_wt[0] = res[0] * (sds->amplify + 1); + sds->res_wt[1] = res[1] * (sds->amplify + 1); + sds->res_wt[2] = res[2] * (sds->amplify + 1); + sds->dx_wt = dx / (sds->amplify + 1); + smoke_initWaveletBlenderRNA(sds->wt, &(sds->strength)); } /* convert global position to domain cell space */ static void smoke_pos_to_cell(SmokeDomainSettings *sds, float pos[3]) { - mul_m4_v3(sds->imat, pos); - sub_v3_v3(pos, sds->p0); - pos[0] *= 1.0f / sds->cell_size[0]; - pos[1] *= 1.0f / sds->cell_size[1]; - pos[2] *= 1.0f / sds->cell_size[2]; + mul_m4_v3(sds->imat, pos); + sub_v3_v3(pos, sds->p0); + pos[0] *= 1.0f / sds->cell_size[0]; + pos[1] *= 1.0f / sds->cell_size[1]; + pos[2] *= 1.0f / sds->cell_size[2]; } /* set domain transformations and base resolution from object mesh */ -static void smoke_set_domain_from_mesh(SmokeDomainSettings *sds, Object *ob, Mesh *me, bool init_resolution) +static void smoke_set_domain_from_mesh(SmokeDomainSettings *sds, + Object *ob, + Mesh *me, + bool init_resolution) { - size_t i; - float min[3] = {FLT_MAX, FLT_MAX, FLT_MAX}, max[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX}; - float size[3]; - MVert *verts = me->mvert; - float scale = 0.0; - int res; - - res = sds->maxres; - - // get BB of domain - for (i = 0; i < me->totvert; i++) - { - // min BB - min[0] = MIN2(min[0], verts[i].co[0]); - min[1] = MIN2(min[1], verts[i].co[1]); - min[2] = MIN2(min[2], verts[i].co[2]); - - // max BB - max[0] = MAX2(max[0], verts[i].co[0]); - max[1] = MAX2(max[1], verts[i].co[1]); - max[2] = MAX2(max[2], verts[i].co[2]); - } - - /* set domain bounds */ - copy_v3_v3(sds->p0, min); - copy_v3_v3(sds->p1, max); - sds->dx = 1.0f / res; - - /* calculate domain dimensions */ - sub_v3_v3v3(size, max, min); - if (init_resolution) { - zero_v3_int(sds->base_res); - copy_v3_v3(sds->cell_size, size); - } - /* apply object scale */ - for (i = 0; i < 3; i++) { - size[i] = fabsf(size[i] * ob->scale[i]); - } - copy_v3_v3(sds->global_size, size); - copy_v3_v3(sds->dp0, min); - - invert_m4_m4(sds->imat, ob->obmat); - - // prevent crash when initializing a plane as domain - if (!init_resolution || (size[0] < FLT_EPSILON) || (size[1] < FLT_EPSILON) || (size[2] < FLT_EPSILON)) - return; - - /* define grid resolutions from longest domain side */ - if (size[0] >= MAX2(size[1], size[2])) { - scale = res / size[0]; - sds->scale = size[0] / fabsf(ob->scale[0]); - sds->base_res[0] = res; - sds->base_res[1] = max_ii((int)(size[1] * scale + 0.5f), 4); - sds->base_res[2] = max_ii((int)(size[2] * scale + 0.5f), 4); - } - else if (size[1] >= MAX2(size[0], size[2])) { - scale = res / size[1]; - sds->scale = size[1] / fabsf(ob->scale[1]); - sds->base_res[0] = max_ii((int)(size[0] * scale + 0.5f), 4); - sds->base_res[1] = res; - sds->base_res[2] = max_ii((int)(size[2] * scale + 0.5f), 4); - } - else { - scale = res / size[2]; - sds->scale = size[2] / fabsf(ob->scale[2]); - sds->base_res[0] = max_ii((int)(size[0] * scale + 0.5f), 4); - sds->base_res[1] = max_ii((int)(size[1] * scale + 0.5f), 4); - sds->base_res[2] = res; - } - - /* set cell size */ - sds->cell_size[0] /= (float)sds->base_res[0]; - sds->cell_size[1] /= (float)sds->base_res[1]; - sds->cell_size[2] /= (float)sds->base_res[2]; + size_t i; + float min[3] = {FLT_MAX, FLT_MAX, FLT_MAX}, max[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX}; + float size[3]; + MVert *verts = me->mvert; + float scale = 0.0; + int res; + + res = sds->maxres; + + // get BB of domain + for (i = 0; i < me->totvert; i++) { + // min BB + min[0] = MIN2(min[0], verts[i].co[0]); + min[1] = MIN2(min[1], verts[i].co[1]); + min[2] = MIN2(min[2], verts[i].co[2]); + + // max BB + max[0] = MAX2(max[0], verts[i].co[0]); + max[1] = MAX2(max[1], verts[i].co[1]); + max[2] = MAX2(max[2], verts[i].co[2]); + } + + /* set domain bounds */ + copy_v3_v3(sds->p0, min); + copy_v3_v3(sds->p1, max); + sds->dx = 1.0f / res; + + /* calculate domain dimensions */ + sub_v3_v3v3(size, max, min); + if (init_resolution) { + zero_v3_int(sds->base_res); + copy_v3_v3(sds->cell_size, size); + } + /* apply object scale */ + for (i = 0; i < 3; i++) { + size[i] = fabsf(size[i] * ob->scale[i]); + } + copy_v3_v3(sds->global_size, size); + copy_v3_v3(sds->dp0, min); + + invert_m4_m4(sds->imat, ob->obmat); + + // prevent crash when initializing a plane as domain + if (!init_resolution || (size[0] < FLT_EPSILON) || (size[1] < FLT_EPSILON) || + (size[2] < FLT_EPSILON)) + return; + + /* define grid resolutions from longest domain side */ + if (size[0] >= MAX2(size[1], size[2])) { + scale = res / size[0]; + sds->scale = size[0] / fabsf(ob->scale[0]); + sds->base_res[0] = res; + sds->base_res[1] = max_ii((int)(size[1] * scale + 0.5f), 4); + sds->base_res[2] = max_ii((int)(size[2] * scale + 0.5f), 4); + } + else if (size[1] >= MAX2(size[0], size[2])) { + scale = res / size[1]; + sds->scale = size[1] / fabsf(ob->scale[1]); + sds->base_res[0] = max_ii((int)(size[0] * scale + 0.5f), 4); + sds->base_res[1] = res; + sds->base_res[2] = max_ii((int)(size[2] * scale + 0.5f), 4); + } + else { + scale = res / size[2]; + sds->scale = size[2] / fabsf(ob->scale[2]); + sds->base_res[0] = max_ii((int)(size[0] * scale + 0.5f), 4); + sds->base_res[1] = max_ii((int)(size[1] * scale + 0.5f), 4); + sds->base_res[2] = res; + } + + /* set cell size */ + sds->cell_size[0] /= (float)sds->base_res[0]; + sds->cell_size[1] /= (float)sds->base_res[1]; + sds->cell_size[2] /= (float)sds->base_res[2]; } static int smokeModifier_init(SmokeModifierData *smd, Object *ob, int scene_framenr, Mesh *me) { - if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain && !smd->domain->fluid) - { - SmokeDomainSettings *sds = smd->domain; - int res[3]; - /* set domain dimensions from mesh */ - smoke_set_domain_from_mesh(sds, ob, me, true); - /* reset domain values */ - zero_v3_int(sds->shift); - zero_v3(sds->shift_f); - add_v3_fl(sds->shift_f, 0.5f); - zero_v3(sds->prev_loc); - mul_m4_v3(ob->obmat, sds->prev_loc); - copy_m4_m4(sds->obmat, ob->obmat); - - /* set resolutions */ - if (smd->domain->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) { - res[0] = res[1] = res[2] = 1; /* use minimum res for adaptive init */ - } - else { - copy_v3_v3_int(res, sds->base_res); - } - copy_v3_v3_int(sds->res, res); - sds->total_cells = sds->res[0] * sds->res[1] * sds->res[2]; - sds->res_min[0] = sds->res_min[1] = sds->res_min[2] = 0; - copy_v3_v3_int(sds->res_max, res); - - /* allocate fluid */ - BKE_smoke_reallocate_fluid(sds, sds->dx, sds->res, 0); - - smd->time = scene_framenr; - - /* allocate highres fluid */ - if (sds->flags & MOD_SMOKE_HIGHRES) { - BKE_smoke_reallocate_highres_fluid(sds, sds->dx, sds->res, 0); - } - /* allocate shadow buffer */ - if (!sds->shadow) - sds->shadow = MEM_callocN(sizeof(float) * sds->res[0] * sds->res[1] * sds->res[2], "SmokeDomainShadow"); - - return 1; - } - else if ((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow) - { - smd->time = scene_framenr; - - return 1; - } - else if ((smd->type & MOD_SMOKE_TYPE_COLL)) - { - if (!smd->coll) - { - smokeModifier_createType(smd); - } - - smd->time = scene_framenr; - - return 1; - } - - return 2; + if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain && !smd->domain->fluid) { + SmokeDomainSettings *sds = smd->domain; + int res[3]; + /* set domain dimensions from mesh */ + smoke_set_domain_from_mesh(sds, ob, me, true); + /* reset domain values */ + zero_v3_int(sds->shift); + zero_v3(sds->shift_f); + add_v3_fl(sds->shift_f, 0.5f); + zero_v3(sds->prev_loc); + mul_m4_v3(ob->obmat, sds->prev_loc); + copy_m4_m4(sds->obmat, ob->obmat); + + /* set resolutions */ + if (smd->domain->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) { + res[0] = res[1] = res[2] = 1; /* use minimum res for adaptive init */ + } + else { + copy_v3_v3_int(res, sds->base_res); + } + copy_v3_v3_int(sds->res, res); + sds->total_cells = sds->res[0] * sds->res[1] * sds->res[2]; + sds->res_min[0] = sds->res_min[1] = sds->res_min[2] = 0; + copy_v3_v3_int(sds->res_max, res); + + /* allocate fluid */ + BKE_smoke_reallocate_fluid(sds, sds->dx, sds->res, 0); + + smd->time = scene_framenr; + + /* allocate highres fluid */ + if (sds->flags & MOD_SMOKE_HIGHRES) { + BKE_smoke_reallocate_highres_fluid(sds, sds->dx, sds->res, 0); + } + /* allocate shadow buffer */ + if (!sds->shadow) + sds->shadow = MEM_callocN(sizeof(float) * sds->res[0] * sds->res[1] * sds->res[2], + "SmokeDomainShadow"); + + return 1; + } + else if ((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow) { + smd->time = scene_framenr; + + return 1; + } + else if ((smd->type & MOD_SMOKE_TYPE_COLL)) { + if (!smd->coll) { + smokeModifier_createType(smd); + } + + smd->time = scene_framenr; + + return 1; + } + + return 2; } #endif /* WITH_SMOKE */ static void smokeModifier_freeDomain(SmokeModifierData *smd) { - if (smd->domain) - { - if (smd->domain->shadow) - MEM_freeN(smd->domain->shadow); - smd->domain->shadow = NULL; + if (smd->domain) { + if (smd->domain->shadow) + MEM_freeN(smd->domain->shadow); + smd->domain->shadow = NULL; - if (smd->domain->fluid) - smoke_free(smd->domain->fluid); + if (smd->domain->fluid) + smoke_free(smd->domain->fluid); - if (smd->domain->fluid_mutex) - BLI_rw_mutex_free(smd->domain->fluid_mutex); + if (smd->domain->fluid_mutex) + BLI_rw_mutex_free(smd->domain->fluid_mutex); - if (smd->domain->wt) - smoke_turbulence_free(smd->domain->wt); + if (smd->domain->wt) + smoke_turbulence_free(smd->domain->wt); - if (smd->domain->effector_weights) - MEM_freeN(smd->domain->effector_weights); - smd->domain->effector_weights = NULL; + if (smd->domain->effector_weights) + MEM_freeN(smd->domain->effector_weights); + smd->domain->effector_weights = NULL; - if (!(smd->modifier.flag & eModifierFlag_SharedCaches)) { - BKE_ptcache_free_list(&(smd->domain->ptcaches[0])); - smd->domain->point_cache[0] = NULL; - } + if (!(smd->modifier.flag & eModifierFlag_SharedCaches)) { + BKE_ptcache_free_list(&(smd->domain->ptcaches[0])); + smd->domain->point_cache[0] = NULL; + } - if (smd->domain->coba) { - MEM_freeN(smd->domain->coba); - } + if (smd->domain->coba) { + MEM_freeN(smd->domain->coba); + } - MEM_freeN(smd->domain); - smd->domain = NULL; - } + MEM_freeN(smd->domain); + smd->domain = NULL; + } } static void smokeModifier_freeFlow(SmokeModifierData *smd) { - if (smd->flow) - { - if (smd->flow->mesh) BKE_id_free(NULL, smd->flow->mesh); - if (smd->flow->verts_old) MEM_freeN(smd->flow->verts_old); - MEM_freeN(smd->flow); - smd->flow = NULL; - } + if (smd->flow) { + if (smd->flow->mesh) + BKE_id_free(NULL, smd->flow->mesh); + if (smd->flow->verts_old) + MEM_freeN(smd->flow->verts_old); + MEM_freeN(smd->flow); + smd->flow = NULL; + } } static void smokeModifier_freeCollision(SmokeModifierData *smd) { - if (smd->coll) - { - SmokeCollSettings *scs = smd->coll; - - if (scs->numverts) - { - if (scs->verts_old) - { - MEM_freeN(scs->verts_old); - scs->verts_old = NULL; - } - } - - if (smd->coll->mesh) - BKE_id_free(NULL, smd->coll->mesh); - smd->coll->mesh = NULL; - - MEM_freeN(smd->coll); - smd->coll = NULL; - } + if (smd->coll) { + SmokeCollSettings *scs = smd->coll; + + if (scs->numverts) { + if (scs->verts_old) { + MEM_freeN(scs->verts_old); + scs->verts_old = NULL; + } + } + + if (smd->coll->mesh) + BKE_id_free(NULL, smd->coll->mesh); + smd->coll->mesh = NULL; + + MEM_freeN(smd->coll); + smd->coll = NULL; + } } void smokeModifier_reset_turbulence(struct SmokeModifierData *smd) { - if (smd && smd->domain && smd->domain->wt) - { - smoke_turbulence_free(smd->domain->wt); - smd->domain->wt = NULL; - } + if (smd && smd->domain && smd->domain->wt) { + smoke_turbulence_free(smd->domain->wt); + smd->domain->wt = NULL; + } } static void smokeModifier_reset_ex(struct SmokeModifierData *smd, bool need_lock) { - if (smd) - { - if (smd->domain) - { - if (smd->domain->shadow) - MEM_freeN(smd->domain->shadow); - smd->domain->shadow = NULL; - - if (smd->domain->fluid) - { - if (need_lock) - BLI_rw_mutex_lock(smd->domain->fluid_mutex, THREAD_LOCK_WRITE); - - smoke_free(smd->domain->fluid); - smd->domain->fluid = NULL; - - if (need_lock) - BLI_rw_mutex_unlock(smd->domain->fluid_mutex); - } - - smokeModifier_reset_turbulence(smd); - - smd->time = -1; - smd->domain->total_cells = 0; - smd->domain->active_fields = 0; - } - else if (smd->flow) - { - if (smd->flow->verts_old) MEM_freeN(smd->flow->verts_old); - smd->flow->verts_old = NULL; - smd->flow->numverts = 0; - } - else if (smd->coll) - { - SmokeCollSettings *scs = smd->coll; - - if (scs->numverts && scs->verts_old) - { - MEM_freeN(scs->verts_old); - scs->verts_old = NULL; - } - } - } + if (smd) { + if (smd->domain) { + if (smd->domain->shadow) + MEM_freeN(smd->domain->shadow); + smd->domain->shadow = NULL; + + if (smd->domain->fluid) { + if (need_lock) + BLI_rw_mutex_lock(smd->domain->fluid_mutex, THREAD_LOCK_WRITE); + + smoke_free(smd->domain->fluid); + smd->domain->fluid = NULL; + + if (need_lock) + BLI_rw_mutex_unlock(smd->domain->fluid_mutex); + } + + smokeModifier_reset_turbulence(smd); + + smd->time = -1; + smd->domain->total_cells = 0; + smd->domain->active_fields = 0; + } + else if (smd->flow) { + if (smd->flow->verts_old) + MEM_freeN(smd->flow->verts_old); + smd->flow->verts_old = NULL; + smd->flow->numverts = 0; + } + else if (smd->coll) { + SmokeCollSettings *scs = smd->coll; + + if (scs->numverts && scs->verts_old) { + MEM_freeN(scs->verts_old); + scs->verts_old = NULL; + } + } + } } void smokeModifier_reset(struct SmokeModifierData *smd) { - smokeModifier_reset_ex(smd, true); + smokeModifier_reset_ex(smd, true); } void smokeModifier_free(SmokeModifierData *smd) { - if (smd) - { - smokeModifier_freeDomain(smd); - smokeModifier_freeFlow(smd); - smokeModifier_freeCollision(smd); - } + if (smd) { + smokeModifier_freeDomain(smd); + smokeModifier_freeFlow(smd); + smokeModifier_freeCollision(smd); + } } void smokeModifier_createType(struct SmokeModifierData *smd) { - if (smd) - { - if (smd->type & MOD_SMOKE_TYPE_DOMAIN) - { - if (smd->domain) - smokeModifier_freeDomain(smd); - - smd->domain = MEM_callocN(sizeof(SmokeDomainSettings), "SmokeDomain"); - - smd->domain->smd = smd; - - smd->domain->point_cache[0] = BKE_ptcache_add(&(smd->domain->ptcaches[0])); - smd->domain->point_cache[0]->flag |= PTCACHE_DISK_CACHE; - smd->domain->point_cache[0]->step = 1; - - /* Deprecated */ - smd->domain->point_cache[1] = NULL; - BLI_listbase_clear(&smd->domain->ptcaches[1]); - /* set some standard values */ - smd->domain->fluid = NULL; - smd->domain->fluid_mutex = BLI_rw_mutex_alloc(); - smd->domain->wt = NULL; - smd->domain->eff_group = NULL; - smd->domain->fluid_group = NULL; - smd->domain->coll_group = NULL; - smd->domain->maxres = 32; - smd->domain->amplify = 1; - smd->domain->alpha = -0.001; - smd->domain->beta = 0.1; - smd->domain->time_scale = 1.0; - smd->domain->vorticity = 2.0; - smd->domain->border_collisions = SM_BORDER_OPEN; // open domain - smd->domain->flags = MOD_SMOKE_DISSOLVE_LOG; - smd->domain->highres_sampling = SM_HRES_FULLSAMPLE; - smd->domain->strength = 2.0; - smd->domain->noise = MOD_SMOKE_NOISEWAVE; - smd->domain->diss_speed = 5; - smd->domain->active_fields = 0; - - smd->domain->adapt_margin = 4; - smd->domain->adapt_res = 0; - smd->domain->adapt_threshold = 0.02f; - - smd->domain->burning_rate = 0.75f; - smd->domain->flame_smoke = 1.0f; - smd->domain->flame_vorticity = 0.5f; - smd->domain->flame_ignition = 1.5f; - smd->domain->flame_max_temp = 3.0f; - /* color */ - smd->domain->flame_smoke_color[0] = 0.7f; - smd->domain->flame_smoke_color[1] = 0.7f; - smd->domain->flame_smoke_color[2] = 0.7f; - - smd->domain->viewsettings = MOD_SMOKE_VIEW_SHOW_HIGHRES; - smd->domain->effector_weights = BKE_effector_add_weights(NULL); + if (smd) { + if (smd->type & MOD_SMOKE_TYPE_DOMAIN) { + if (smd->domain) + smokeModifier_freeDomain(smd); + + smd->domain = MEM_callocN(sizeof(SmokeDomainSettings), "SmokeDomain"); + + smd->domain->smd = smd; + + smd->domain->point_cache[0] = BKE_ptcache_add(&(smd->domain->ptcaches[0])); + smd->domain->point_cache[0]->flag |= PTCACHE_DISK_CACHE; + smd->domain->point_cache[0]->step = 1; + + /* Deprecated */ + smd->domain->point_cache[1] = NULL; + BLI_listbase_clear(&smd->domain->ptcaches[1]); + /* set some standard values */ + smd->domain->fluid = NULL; + smd->domain->fluid_mutex = BLI_rw_mutex_alloc(); + smd->domain->wt = NULL; + smd->domain->eff_group = NULL; + smd->domain->fluid_group = NULL; + smd->domain->coll_group = NULL; + smd->domain->maxres = 32; + smd->domain->amplify = 1; + smd->domain->alpha = -0.001; + smd->domain->beta = 0.1; + smd->domain->time_scale = 1.0; + smd->domain->vorticity = 2.0; + smd->domain->border_collisions = SM_BORDER_OPEN; // open domain + smd->domain->flags = MOD_SMOKE_DISSOLVE_LOG; + smd->domain->highres_sampling = SM_HRES_FULLSAMPLE; + smd->domain->strength = 2.0; + smd->domain->noise = MOD_SMOKE_NOISEWAVE; + smd->domain->diss_speed = 5; + smd->domain->active_fields = 0; + + smd->domain->adapt_margin = 4; + smd->domain->adapt_res = 0; + smd->domain->adapt_threshold = 0.02f; + + smd->domain->burning_rate = 0.75f; + smd->domain->flame_smoke = 1.0f; + smd->domain->flame_vorticity = 0.5f; + smd->domain->flame_ignition = 1.5f; + smd->domain->flame_max_temp = 3.0f; + /* color */ + smd->domain->flame_smoke_color[0] = 0.7f; + smd->domain->flame_smoke_color[1] = 0.7f; + smd->domain->flame_smoke_color[2] = 0.7f; + + smd->domain->viewsettings = MOD_SMOKE_VIEW_SHOW_HIGHRES; + smd->domain->effector_weights = BKE_effector_add_weights(NULL); #ifdef WITH_OPENVDB_BLOSC - smd->domain->openvdb_comp = VDB_COMPRESSION_BLOSC; + smd->domain->openvdb_comp = VDB_COMPRESSION_BLOSC; #else - smd->domain->openvdb_comp = VDB_COMPRESSION_ZIP; + smd->domain->openvdb_comp = VDB_COMPRESSION_ZIP; #endif - smd->domain->data_depth = 0; - smd->domain->cache_file_format = PTCACHE_FILE_PTCACHE; - - smd->domain->display_thickness = 1.0f; - smd->domain->slice_method = MOD_SMOKE_SLICE_VIEW_ALIGNED; - smd->domain->axis_slice_method = AXIS_SLICE_FULL; - smd->domain->slice_per_voxel = 5.0f; - smd->domain->slice_depth = 0.5f; - smd->domain->slice_axis = 0; - smd->domain->vector_scale = 1.0f; - - smd->domain->coba = NULL; - smd->domain->coba_field = FLUID_FIELD_DENSITY; - - smd->domain->clipping = 1e-3f; - } - else if (smd->type & MOD_SMOKE_TYPE_FLOW) - { - if (smd->flow) - smokeModifier_freeFlow(smd); - - smd->flow = MEM_callocN(sizeof(SmokeFlowSettings), "SmokeFlow"); - - smd->flow->smd = smd; - - /* set some standard values */ - smd->flow->density = 1.0f; - smd->flow->fuel_amount = 1.0f; - smd->flow->temp = 1.0f; - smd->flow->flags = MOD_SMOKE_FLOW_ABSOLUTE | MOD_SMOKE_FLOW_USE_PART_SIZE; - smd->flow->vel_multi = 1.0f; - smd->flow->volume_density = 0.0f; - smd->flow->surface_distance = 1.5f; - smd->flow->source = MOD_SMOKE_FLOW_SOURCE_MESH; - smd->flow->texture_size = 1.0f; - smd->flow->particle_size = 1.0f; - smd->flow->subframes = 0; - - smd->flow->color[0] = 0.7f; - smd->flow->color[1] = 0.7f; - smd->flow->color[2] = 0.7f; - - smd->flow->mesh = NULL; - smd->flow->psys = NULL; - - } - else if (smd->type & MOD_SMOKE_TYPE_COLL) - { - if (smd->coll) - smokeModifier_freeCollision(smd); - - smd->coll = MEM_callocN(sizeof(SmokeCollSettings), "SmokeColl"); - - smd->coll->smd = smd; - smd->coll->verts_old = NULL; - smd->coll->numverts = 0; - smd->coll->type = 0; // static obstacle - smd->coll->mesh = NULL; - } - } + smd->domain->data_depth = 0; + smd->domain->cache_file_format = PTCACHE_FILE_PTCACHE; + + smd->domain->display_thickness = 1.0f; + smd->domain->slice_method = MOD_SMOKE_SLICE_VIEW_ALIGNED; + smd->domain->axis_slice_method = AXIS_SLICE_FULL; + smd->domain->slice_per_voxel = 5.0f; + smd->domain->slice_depth = 0.5f; + smd->domain->slice_axis = 0; + smd->domain->vector_scale = 1.0f; + + smd->domain->coba = NULL; + smd->domain->coba_field = FLUID_FIELD_DENSITY; + + smd->domain->clipping = 1e-3f; + } + else if (smd->type & MOD_SMOKE_TYPE_FLOW) { + if (smd->flow) + smokeModifier_freeFlow(smd); + + smd->flow = MEM_callocN(sizeof(SmokeFlowSettings), "SmokeFlow"); + + smd->flow->smd = smd; + + /* set some standard values */ + smd->flow->density = 1.0f; + smd->flow->fuel_amount = 1.0f; + smd->flow->temp = 1.0f; + smd->flow->flags = MOD_SMOKE_FLOW_ABSOLUTE | MOD_SMOKE_FLOW_USE_PART_SIZE; + smd->flow->vel_multi = 1.0f; + smd->flow->volume_density = 0.0f; + smd->flow->surface_distance = 1.5f; + smd->flow->source = MOD_SMOKE_FLOW_SOURCE_MESH; + smd->flow->texture_size = 1.0f; + smd->flow->particle_size = 1.0f; + smd->flow->subframes = 0; + + smd->flow->color[0] = 0.7f; + smd->flow->color[1] = 0.7f; + smd->flow->color[2] = 0.7f; + + smd->flow->mesh = NULL; + smd->flow->psys = NULL; + } + else if (smd->type & MOD_SMOKE_TYPE_COLL) { + if (smd->coll) + smokeModifier_freeCollision(smd); + + smd->coll = MEM_callocN(sizeof(SmokeCollSettings), "SmokeColl"); + + smd->coll->smd = smd; + smd->coll->verts_old = NULL; + smd->coll->numverts = 0; + smd->coll->type = 0; // static obstacle + smd->coll->mesh = NULL; + } + } } -void smokeModifier_copy(const struct SmokeModifierData *smd, struct SmokeModifierData *tsmd, const int flag) +void smokeModifier_copy(const struct SmokeModifierData *smd, + struct SmokeModifierData *tsmd, + const int flag) { - tsmd->type = smd->type; - tsmd->time = smd->time; - - smokeModifier_createType(tsmd); - - if (tsmd->domain) { - SmokeDomainSettings *tsds = tsmd->domain; - SmokeDomainSettings *sds = smd->domain; - - BKE_ptcache_free_list(&(tsds->ptcaches[0])); - - if (flag & LIB_ID_CREATE_NO_MAIN) { - /* Share the cache with the original object's modifier. */ - tsmd->modifier.flag |= eModifierFlag_SharedCaches; - tsds->point_cache[0] = sds->point_cache[0]; - tsds->ptcaches[0] = sds->ptcaches[0]; - } - else { - tsds->point_cache[0] = BKE_ptcache_copy_list(&(tsds->ptcaches[0]), &(sds->ptcaches[0]), flag); - } - - tsds->fluid_group = sds->fluid_group; - tsds->coll_group = sds->coll_group; - - tsds->adapt_margin = sds->adapt_margin; - tsds->adapt_res = sds->adapt_res; - tsds->adapt_threshold = sds->adapt_threshold; - - tsds->alpha = sds->alpha; - tsds->beta = sds->beta; - tsds->amplify = sds->amplify; - tsds->maxres = sds->maxres; - tsds->flags = sds->flags; - tsds->highres_sampling = sds->highres_sampling; - tsds->viewsettings = sds->viewsettings; - tsds->noise = sds->noise; - tsds->diss_speed = sds->diss_speed; - tsds->strength = sds->strength; - - tsds->border_collisions = sds->border_collisions; - tsds->vorticity = sds->vorticity; - tsds->time_scale = sds->time_scale; - - tsds->burning_rate = sds->burning_rate; - tsds->flame_smoke = sds->flame_smoke; - tsds->flame_vorticity = sds->flame_vorticity; - tsds->flame_ignition = sds->flame_ignition; - tsds->flame_max_temp = sds->flame_max_temp; - copy_v3_v3(tsds->flame_smoke_color, sds->flame_smoke_color); - - MEM_freeN(tsds->effector_weights); - tsds->effector_weights = MEM_dupallocN(sds->effector_weights); - tsds->openvdb_comp = sds->openvdb_comp; - tsds->data_depth = sds->data_depth; - tsds->cache_file_format = sds->cache_file_format; - - tsds->display_thickness = sds->display_thickness; - tsds->slice_method = sds->slice_method; - tsds->axis_slice_method = sds->axis_slice_method; - tsds->slice_per_voxel = sds->slice_per_voxel; - tsds->slice_depth = sds->slice_depth; - tsds->slice_axis = sds->slice_axis; - tsds->interp_method = sds->interp_method; - tsds->draw_velocity = sds->draw_velocity; - tsds->vector_draw_type = sds->vector_draw_type; - tsds->vector_scale = sds->vector_scale; - - tsds->use_coba = sds->use_coba; - tsds->coba_field = sds->coba_field; - if (sds->coba) { - tsds->coba = MEM_dupallocN(sds->coba); - } - - tsds->clipping = sds->clipping; - } - else if (tsmd->flow) { - SmokeFlowSettings *tsfs = tsmd->flow; - SmokeFlowSettings *sfs = smd->flow; - - tsfs->psys = sfs->psys; - tsfs->noise_texture = sfs->noise_texture; - - tsfs->vel_multi = sfs->vel_multi; - tsfs->vel_normal = sfs->vel_normal; - tsfs->vel_random = sfs->vel_random; - - tsfs->density = sfs->density; - copy_v3_v3(tsfs->color, sfs->color); - tsfs->fuel_amount = sfs->fuel_amount; - tsfs->temp = sfs->temp; - tsfs->volume_density = sfs->volume_density; - tsfs->surface_distance = sfs->surface_distance; - tsfs->particle_size = sfs->particle_size; - tsfs->subframes = sfs->subframes; - - tsfs->texture_size = sfs->texture_size; - tsfs->texture_offset = sfs->texture_offset; - BLI_strncpy(tsfs->uvlayer_name, sfs->uvlayer_name, sizeof(tsfs->uvlayer_name)); - tsfs->vgroup_density = sfs->vgroup_density; - - tsfs->type = sfs->type; - tsfs->source = sfs->source; - tsfs->texture_type = sfs->texture_type; - tsfs->flags = sfs->flags; - } - else if (tsmd->coll) { - /* leave it as initialized, collision settings is mostly caches */ - } + tsmd->type = smd->type; + tsmd->time = smd->time; + + smokeModifier_createType(tsmd); + + if (tsmd->domain) { + SmokeDomainSettings *tsds = tsmd->domain; + SmokeDomainSettings *sds = smd->domain; + + BKE_ptcache_free_list(&(tsds->ptcaches[0])); + + if (flag & LIB_ID_CREATE_NO_MAIN) { + /* Share the cache with the original object's modifier. */ + tsmd->modifier.flag |= eModifierFlag_SharedCaches; + tsds->point_cache[0] = sds->point_cache[0]; + tsds->ptcaches[0] = sds->ptcaches[0]; + } + else { + tsds->point_cache[0] = BKE_ptcache_copy_list( + &(tsds->ptcaches[0]), &(sds->ptcaches[0]), flag); + } + + tsds->fluid_group = sds->fluid_group; + tsds->coll_group = sds->coll_group; + + tsds->adapt_margin = sds->adapt_margin; + tsds->adapt_res = sds->adapt_res; + tsds->adapt_threshold = sds->adapt_threshold; + + tsds->alpha = sds->alpha; + tsds->beta = sds->beta; + tsds->amplify = sds->amplify; + tsds->maxres = sds->maxres; + tsds->flags = sds->flags; + tsds->highres_sampling = sds->highres_sampling; + tsds->viewsettings = sds->viewsettings; + tsds->noise = sds->noise; + tsds->diss_speed = sds->diss_speed; + tsds->strength = sds->strength; + + tsds->border_collisions = sds->border_collisions; + tsds->vorticity = sds->vorticity; + tsds->time_scale = sds->time_scale; + + tsds->burning_rate = sds->burning_rate; + tsds->flame_smoke = sds->flame_smoke; + tsds->flame_vorticity = sds->flame_vorticity; + tsds->flame_ignition = sds->flame_ignition; + tsds->flame_max_temp = sds->flame_max_temp; + copy_v3_v3(tsds->flame_smoke_color, sds->flame_smoke_color); + + MEM_freeN(tsds->effector_weights); + tsds->effector_weights = MEM_dupallocN(sds->effector_weights); + tsds->openvdb_comp = sds->openvdb_comp; + tsds->data_depth = sds->data_depth; + tsds->cache_file_format = sds->cache_file_format; + + tsds->display_thickness = sds->display_thickness; + tsds->slice_method = sds->slice_method; + tsds->axis_slice_method = sds->axis_slice_method; + tsds->slice_per_voxel = sds->slice_per_voxel; + tsds->slice_depth = sds->slice_depth; + tsds->slice_axis = sds->slice_axis; + tsds->interp_method = sds->interp_method; + tsds->draw_velocity = sds->draw_velocity; + tsds->vector_draw_type = sds->vector_draw_type; + tsds->vector_scale = sds->vector_scale; + + tsds->use_coba = sds->use_coba; + tsds->coba_field = sds->coba_field; + if (sds->coba) { + tsds->coba = MEM_dupallocN(sds->coba); + } + + tsds->clipping = sds->clipping; + } + else if (tsmd->flow) { + SmokeFlowSettings *tsfs = tsmd->flow; + SmokeFlowSettings *sfs = smd->flow; + + tsfs->psys = sfs->psys; + tsfs->noise_texture = sfs->noise_texture; + + tsfs->vel_multi = sfs->vel_multi; + tsfs->vel_normal = sfs->vel_normal; + tsfs->vel_random = sfs->vel_random; + + tsfs->density = sfs->density; + copy_v3_v3(tsfs->color, sfs->color); + tsfs->fuel_amount = sfs->fuel_amount; + tsfs->temp = sfs->temp; + tsfs->volume_density = sfs->volume_density; + tsfs->surface_distance = sfs->surface_distance; + tsfs->particle_size = sfs->particle_size; + tsfs->subframes = sfs->subframes; + + tsfs->texture_size = sfs->texture_size; + tsfs->texture_offset = sfs->texture_offset; + BLI_strncpy(tsfs->uvlayer_name, sfs->uvlayer_name, sizeof(tsfs->uvlayer_name)); + tsfs->vgroup_density = sfs->vgroup_density; + + tsfs->type = sfs->type; + tsfs->source = sfs->source; + tsfs->texture_type = sfs->texture_type; + tsfs->flags = sfs->flags; + } + else if (tsmd->coll) { + /* leave it as initialized, collision settings is mostly caches */ + } } #ifdef WITH_SMOKE // forward declaration static void smoke_calc_transparency(SmokeDomainSettings *sds, ViewLayer *view_layer); -static float calc_voxel_transp(float *result, float *input, int res[3], int *pixel, float *tRay, float correct); +static float calc_voxel_transp( + float *result, float *input, int res[3], int *pixel, float *tRay, float correct); static int get_light(ViewLayer *view_layer, float *light) { - Base *base_tmp = NULL; - int found_light = 0; - - // try to find a lamp, preferably local - for (base_tmp = FIRSTBASE(view_layer); base_tmp; base_tmp = base_tmp->next) { - if (base_tmp->object->type == OB_LAMP) { - Light *la = base_tmp->object->data; - - if (la->type == LA_LOCAL) { - copy_v3_v3(light, base_tmp->object->obmat[3]); - return 1; - } - else if (!found_light) { - copy_v3_v3(light, base_tmp->object->obmat[3]); - found_light = 1; - } - } - } - - return found_light; + Base *base_tmp = NULL; + int found_light = 0; + + // try to find a lamp, preferably local + for (base_tmp = FIRSTBASE(view_layer); base_tmp; base_tmp = base_tmp->next) { + if (base_tmp->object->type == OB_LAMP) { + Light *la = base_tmp->object->data; + + if (la->type == LA_LOCAL) { + copy_v3_v3(light, base_tmp->object->obmat[3]); + return 1; + } + else if (!found_light) { + copy_v3_v3(light, base_tmp->object->obmat[3]); + found_light = 1; + } + } + } + + return found_light; } /********************************************************** @@ -744,256 +786,277 @@ static int get_light(ViewLayer *view_layer, float *light) **********************************************************/ typedef struct ObstaclesFromDMData { - SmokeDomainSettings *sds; - const MVert *mvert; - const MLoop *mloop; - const MLoopTri *looptri; - BVHTreeFromMesh *tree; - unsigned char *obstacle_map; - - bool has_velocity; - float *vert_vel; - float *velocityX, *velocityY, *velocityZ; - int *num_obstacles; + SmokeDomainSettings *sds; + const MVert *mvert; + const MLoop *mloop; + const MLoopTri *looptri; + BVHTreeFromMesh *tree; + unsigned char *obstacle_map; + + bool has_velocity; + float *vert_vel; + float *velocityX, *velocityY, *velocityZ; + int *num_obstacles; } ObstaclesFromDMData; -static void obstacles_from_mesh_task_cb( - void *__restrict userdata, - const int z, - const ParallelRangeTLS *__restrict UNUSED(tls)) +static void obstacles_from_mesh_task_cb(void *__restrict userdata, + const int z, + const ParallelRangeTLS *__restrict UNUSED(tls)) { - ObstaclesFromDMData *data = userdata; - SmokeDomainSettings *sds = data->sds; - - /* slightly rounded-up sqrt(3 * (0.5)^2) == max. distance of cell boundary along the diagonal */ - const float surface_distance = 0.867f; - - for (int x = sds->res_min[0]; x < sds->res_max[0]; x++) { - for (int y = sds->res_min[1]; y < sds->res_max[1]; y++) { - const int index = smoke_get_index(x - sds->res_min[0], sds->res[0], y - sds->res_min[1], sds->res[1], z - sds->res_min[2]); - - float ray_start[3] = {(float)x + 0.5f, (float)y + 0.5f, (float)z + 0.5f}; - BVHTreeNearest nearest = {0}; - nearest.index = -1; - nearest.dist_sq = surface_distance * surface_distance; /* find_nearest uses squared distance */ - - /* find the nearest point on the mesh */ - if (BLI_bvhtree_find_nearest(data->tree->tree, ray_start, &nearest, data->tree->nearest_callback, data->tree) != -1) { - const MLoopTri *lt = &data->looptri[nearest.index]; - float weights[3]; - int v1, v2, v3; - - /* calculate barycentric weights for nearest point */ - v1 = data->mloop[lt->tri[0]].v; - v2 = data->mloop[lt->tri[1]].v; - v3 = data->mloop[lt->tri[2]].v; - interp_weights_tri_v3(weights, data->mvert[v1].co, data->mvert[v2].co, data->mvert[v3].co, nearest.co); - - // DG TODO - if (data->has_velocity) - { - /* apply object velocity */ - { - float hit_vel[3]; - interp_v3_v3v3v3(hit_vel, &data->vert_vel[v1 * 3], &data->vert_vel[v2 * 3], &data->vert_vel[v3 * 3], weights); - data->velocityX[index] += hit_vel[0]; - data->velocityY[index] += hit_vel[1]; - data->velocityZ[index] += hit_vel[2]; - } - } - - /* tag obstacle cells */ - data->obstacle_map[index] = 1; - - if (data->has_velocity) { - data->obstacle_map[index] |= 8; - data->num_obstacles[index]++; - } - } - } - } + ObstaclesFromDMData *data = userdata; + SmokeDomainSettings *sds = data->sds; + + /* slightly rounded-up sqrt(3 * (0.5)^2) == max. distance of cell boundary along the diagonal */ + const float surface_distance = 0.867f; + + for (int x = sds->res_min[0]; x < sds->res_max[0]; x++) { + for (int y = sds->res_min[1]; y < sds->res_max[1]; y++) { + const int index = smoke_get_index( + x - sds->res_min[0], sds->res[0], y - sds->res_min[1], sds->res[1], z - sds->res_min[2]); + + float ray_start[3] = {(float)x + 0.5f, (float)y + 0.5f, (float)z + 0.5f}; + BVHTreeNearest nearest = {0}; + nearest.index = -1; + nearest.dist_sq = surface_distance * + surface_distance; /* find_nearest uses squared distance */ + + /* find the nearest point on the mesh */ + if (BLI_bvhtree_find_nearest( + data->tree->tree, ray_start, &nearest, data->tree->nearest_callback, data->tree) != + -1) { + const MLoopTri *lt = &data->looptri[nearest.index]; + float weights[3]; + int v1, v2, v3; + + /* calculate barycentric weights for nearest point */ + v1 = data->mloop[lt->tri[0]].v; + v2 = data->mloop[lt->tri[1]].v; + v3 = data->mloop[lt->tri[2]].v; + interp_weights_tri_v3( + weights, data->mvert[v1].co, data->mvert[v2].co, data->mvert[v3].co, nearest.co); + + // DG TODO + if (data->has_velocity) { + /* apply object velocity */ + { + float hit_vel[3]; + interp_v3_v3v3v3(hit_vel, + &data->vert_vel[v1 * 3], + &data->vert_vel[v2 * 3], + &data->vert_vel[v3 * 3], + weights); + data->velocityX[index] += hit_vel[0]; + data->velocityY[index] += hit_vel[1]; + data->velocityZ[index] += hit_vel[2]; + } + } + + /* tag obstacle cells */ + data->obstacle_map[index] = 1; + + if (data->has_velocity) { + data->obstacle_map[index] |= 8; + data->num_obstacles[index]++; + } + } + } + } } -static void obstacles_from_mesh( - Object *coll_ob, SmokeDomainSettings *sds, SmokeCollSettings *scs, - unsigned char *obstacle_map, float *velocityX, float *velocityY, float *velocityZ, int *num_obstacles, float dt) +static void obstacles_from_mesh(Object *coll_ob, + SmokeDomainSettings *sds, + SmokeCollSettings *scs, + unsigned char *obstacle_map, + float *velocityX, + float *velocityY, + float *velocityZ, + int *num_obstacles, + float dt) { - if (!scs->mesh) return; - { - Mesh *me = NULL; - MVert *mvert = NULL; - const MLoopTri *looptri; - const MLoop *mloop; - BVHTreeFromMesh treeData = {NULL}; - int numverts, i; - - float *vert_vel = NULL; - bool has_velocity = false; - - me = BKE_mesh_copy_for_eval(scs->mesh, true); - BKE_mesh_ensure_normals(me); - mvert = me->mvert; - mloop = me->mloop; - looptri = BKE_mesh_runtime_looptri_ensure(me); - numverts = me->totvert; - - // DG TODO - // if (scs->type > SM_COLL_STATIC) - // if line above is used, the code is in trouble if the object moves but is declared as "does not move" - - { - vert_vel = MEM_callocN(sizeof(float) * numverts * 3, "smoke_obs_velocity"); - - if (scs->numverts != numverts || !scs->verts_old) { - if (scs->verts_old) MEM_freeN(scs->verts_old); - - scs->verts_old = MEM_callocN(sizeof(float) * numverts * 3, "smoke_obs_verts_old"); - scs->numverts = numverts; - } - else { - has_velocity = true; - } - } - - /* Transform collider vertices to - * domain grid space for fast lookups */ - for (i = 0; i < numverts; i++) { - float n[3]; - float co[3]; - - /* vert pos */ - mul_m4_v3(coll_ob->obmat, mvert[i].co); - smoke_pos_to_cell(sds, mvert[i].co); - - /* vert normal */ - normal_short_to_float_v3(n, mvert[i].no); - mul_mat3_m4_v3(coll_ob->obmat, n); - mul_mat3_m4_v3(sds->imat, n); - normalize_v3(n); - normal_float_to_short_v3(mvert[i].no, n); - - /* vert velocity */ - add_v3fl_v3fl_v3i(co, mvert[i].co, sds->shift); - if (has_velocity) - { - sub_v3_v3v3(&vert_vel[i * 3], co, &scs->verts_old[i * 3]); - mul_v3_fl(&vert_vel[i * 3], sds->dx / dt); - } - copy_v3_v3(&scs->verts_old[i * 3], co); - } - - if (BKE_bvhtree_from_mesh_get(&treeData, me, BVHTREE_FROM_LOOPTRI, 4)) { - ObstaclesFromDMData data = { - .sds = sds, .mvert = mvert, .mloop = mloop, .looptri = looptri, - .tree = &treeData, .obstacle_map = obstacle_map, - .has_velocity = has_velocity, .vert_vel = vert_vel, - .velocityX = velocityX, .velocityY = velocityY, .velocityZ = velocityZ, - .num_obstacles = num_obstacles, - }; - ParallelRangeSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC; - BLI_task_parallel_range(sds->res_min[2], sds->res_max[2], - &data, - obstacles_from_mesh_task_cb, - &settings); - } - /* free bvh tree */ - free_bvhtree_from_mesh(&treeData); - BKE_id_free(NULL, me); - - if (vert_vel) MEM_freeN(vert_vel); - } + if (!scs->mesh) + return; + { + Mesh *me = NULL; + MVert *mvert = NULL; + const MLoopTri *looptri; + const MLoop *mloop; + BVHTreeFromMesh treeData = {NULL}; + int numverts, i; + + float *vert_vel = NULL; + bool has_velocity = false; + + me = BKE_mesh_copy_for_eval(scs->mesh, true); + BKE_mesh_ensure_normals(me); + mvert = me->mvert; + mloop = me->mloop; + looptri = BKE_mesh_runtime_looptri_ensure(me); + numverts = me->totvert; + + // DG TODO + // if (scs->type > SM_COLL_STATIC) + // if line above is used, the code is in trouble if the object moves but is declared as "does not move" + + { + vert_vel = MEM_callocN(sizeof(float) * numverts * 3, "smoke_obs_velocity"); + + if (scs->numverts != numverts || !scs->verts_old) { + if (scs->verts_old) + MEM_freeN(scs->verts_old); + + scs->verts_old = MEM_callocN(sizeof(float) * numverts * 3, "smoke_obs_verts_old"); + scs->numverts = numverts; + } + else { + has_velocity = true; + } + } + + /* Transform collider vertices to + * domain grid space for fast lookups */ + for (i = 0; i < numverts; i++) { + float n[3]; + float co[3]; + + /* vert pos */ + mul_m4_v3(coll_ob->obmat, mvert[i].co); + smoke_pos_to_cell(sds, mvert[i].co); + + /* vert normal */ + normal_short_to_float_v3(n, mvert[i].no); + mul_mat3_m4_v3(coll_ob->obmat, n); + mul_mat3_m4_v3(sds->imat, n); + normalize_v3(n); + normal_float_to_short_v3(mvert[i].no, n); + + /* vert velocity */ + add_v3fl_v3fl_v3i(co, mvert[i].co, sds->shift); + if (has_velocity) { + sub_v3_v3v3(&vert_vel[i * 3], co, &scs->verts_old[i * 3]); + mul_v3_fl(&vert_vel[i * 3], sds->dx / dt); + } + copy_v3_v3(&scs->verts_old[i * 3], co); + } + + if (BKE_bvhtree_from_mesh_get(&treeData, me, BVHTREE_FROM_LOOPTRI, 4)) { + ObstaclesFromDMData data = { + .sds = sds, + .mvert = mvert, + .mloop = mloop, + .looptri = looptri, + .tree = &treeData, + .obstacle_map = obstacle_map, + .has_velocity = has_velocity, + .vert_vel = vert_vel, + .velocityX = velocityX, + .velocityY = velocityY, + .velocityZ = velocityZ, + .num_obstacles = num_obstacles, + }; + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC; + BLI_task_parallel_range( + sds->res_min[2], sds->res_max[2], &data, obstacles_from_mesh_task_cb, &settings); + } + /* free bvh tree */ + free_bvhtree_from_mesh(&treeData); + BKE_id_free(NULL, me); + + if (vert_vel) + MEM_freeN(vert_vel); + } } /* Animated obstacles: dx_step = ((x_new - x_old) / totalsteps) * substep */ -static void update_obstacles(Depsgraph *depsgraph, Object *ob, SmokeDomainSettings *sds, float dt, - int UNUSED(substep), int UNUSED(totalsteps)) +static void update_obstacles(Depsgraph *depsgraph, + Object *ob, + SmokeDomainSettings *sds, + float dt, + int UNUSED(substep), + int UNUSED(totalsteps)) { - Object **collobjs = NULL; - unsigned int numcollobj = 0; - - unsigned int collIndex; - unsigned char *obstacles = smoke_get_obstacle(sds->fluid); - float *velx = NULL; - float *vely = NULL; - float *velz = NULL; - float *velxOrig = smoke_get_velocity_x(sds->fluid); - float *velyOrig = smoke_get_velocity_y(sds->fluid); - float *velzOrig = smoke_get_velocity_z(sds->fluid); - float *density = smoke_get_density(sds->fluid); - float *fuel = smoke_get_fuel(sds->fluid); - float *flame = smoke_get_flame(sds->fluid); - float *r = smoke_get_color_r(sds->fluid); - float *g = smoke_get_color_g(sds->fluid); - float *b = smoke_get_color_b(sds->fluid); - unsigned int z; - - int *num_obstacles = MEM_callocN(sizeof(int) * sds->res[0] * sds->res[1] * sds->res[2], "smoke_num_obstacles"); - - smoke_get_ob_velocity(sds->fluid, &velx, &vely, &velz); - - // TODO: delete old obstacle flags - for (z = 0; z < sds->res[0] * sds->res[1] * sds->res[2]; z++) - { - if (obstacles[z] & 8) // Do not delete static obstacles - { - obstacles[z] = 0; - } - - velx[z] = 0; - vely[z] = 0; - velz[z] = 0; - } - - - collobjs = BKE_collision_objects_create(depsgraph, ob, sds->coll_group, &numcollobj, eModifierType_Smoke); - - // update obstacle tags in cells - for (collIndex = 0; collIndex < numcollobj; collIndex++) - { - Object *collob = collobjs[collIndex]; - SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(collob, eModifierType_Smoke); - - // DG TODO: check if modifier is active? - - if ((smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll) - { - SmokeCollSettings *scs = smd2->coll; - obstacles_from_mesh(collob, sds, scs, obstacles, velx, vely, velz, num_obstacles, dt); - } - } - - BKE_collision_objects_free(collobjs); - - /* obstacle cells should not contain any velocity from the smoke simulation */ - for (z = 0; z < sds->res[0] * sds->res[1] * sds->res[2]; z++) - { - if (obstacles[z]) - { - velxOrig[z] = 0; - velyOrig[z] = 0; - velzOrig[z] = 0; - density[z] = 0; - if (fuel) { - fuel[z] = 0; - flame[z] = 0; - } - if (r) { - r[z] = 0; - g[z] = 0; - b[z] = 0; - } - } - /* average velocities from multiple obstacles in one cell */ - if (num_obstacles[z]) { - velx[z] /= num_obstacles[z]; - vely[z] /= num_obstacles[z]; - velz[z] /= num_obstacles[z]; - } - } - - MEM_freeN(num_obstacles); + Object **collobjs = NULL; + unsigned int numcollobj = 0; + + unsigned int collIndex; + unsigned char *obstacles = smoke_get_obstacle(sds->fluid); + float *velx = NULL; + float *vely = NULL; + float *velz = NULL; + float *velxOrig = smoke_get_velocity_x(sds->fluid); + float *velyOrig = smoke_get_velocity_y(sds->fluid); + float *velzOrig = smoke_get_velocity_z(sds->fluid); + float *density = smoke_get_density(sds->fluid); + float *fuel = smoke_get_fuel(sds->fluid); + float *flame = smoke_get_flame(sds->fluid); + float *r = smoke_get_color_r(sds->fluid); + float *g = smoke_get_color_g(sds->fluid); + float *b = smoke_get_color_b(sds->fluid); + unsigned int z; + + int *num_obstacles = MEM_callocN(sizeof(int) * sds->res[0] * sds->res[1] * sds->res[2], + "smoke_num_obstacles"); + + smoke_get_ob_velocity(sds->fluid, &velx, &vely, &velz); + + // TODO: delete old obstacle flags + for (z = 0; z < sds->res[0] * sds->res[1] * sds->res[2]; z++) { + if (obstacles[z] & 8) // Do not delete static obstacles + { + obstacles[z] = 0; + } + + velx[z] = 0; + vely[z] = 0; + velz[z] = 0; + } + + collobjs = BKE_collision_objects_create( + depsgraph, ob, sds->coll_group, &numcollobj, eModifierType_Smoke); + + // update obstacle tags in cells + for (collIndex = 0; collIndex < numcollobj; collIndex++) { + Object *collob = collobjs[collIndex]; + SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(collob, + eModifierType_Smoke); + + // DG TODO: check if modifier is active? + + if ((smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll) { + SmokeCollSettings *scs = smd2->coll; + obstacles_from_mesh(collob, sds, scs, obstacles, velx, vely, velz, num_obstacles, dt); + } + } + + BKE_collision_objects_free(collobjs); + + /* obstacle cells should not contain any velocity from the smoke simulation */ + for (z = 0; z < sds->res[0] * sds->res[1] * sds->res[2]; z++) { + if (obstacles[z]) { + velxOrig[z] = 0; + velyOrig[z] = 0; + velzOrig[z] = 0; + density[z] = 0; + if (fuel) { + fuel[z] = 0; + flame[z] = 0; + } + if (r) { + r[z] = 0; + g[z] = 0; + b[z] = 0; + } + } + /* average velocities from multiple obstacles in one cell */ + if (num_obstacles[z]) { + velx[z] /= num_obstacles[z]; + vely[z] /= num_obstacles[z]; + velz[z] /= num_obstacles[z]; + } + } + + MEM_freeN(num_obstacles); } /********************************************************** @@ -1001,2162 +1064,2484 @@ static void update_obstacles(Depsgraph *depsgraph, Object *ob, SmokeDomainSettin **********************************************************/ typedef struct EmissionMap { - float *influence; - float *influence_high; - float *velocity; - int min[3], max[3], res[3]; - int hmin[3], hmax[3], hres[3]; - int total_cells, valid; + float *influence; + float *influence_high; + float *velocity; + int min[3], max[3], res[3]; + int hmin[3], hmax[3], hres[3]; + int total_cells, valid; } EmissionMap; static void em_boundInsert(EmissionMap *em, float point[3]) { - int i = 0; - if (!em->valid) { - for (; i < 3; i++) { - em->min[i] = (int)floor(point[i]); - em->max[i] = (int)ceil(point[i]); - } - em->valid = 1; - } - else { - for (; i < 3; i++) { - if (point[i] < em->min[i]) em->min[i] = (int)floor(point[i]); - if (point[i] > em->max[i]) em->max[i] = (int)ceil(point[i]); - } - } + int i = 0; + if (!em->valid) { + for (; i < 3; i++) { + em->min[i] = (int)floor(point[i]); + em->max[i] = (int)ceil(point[i]); + } + em->valid = 1; + } + else { + for (; i < 3; i++) { + if (point[i] < em->min[i]) + em->min[i] = (int)floor(point[i]); + if (point[i] > em->max[i]) + em->max[i] = (int)ceil(point[i]); + } + } } -static void clampBoundsInDomain(SmokeDomainSettings *sds, int min[3], int max[3], float *min_vel, float *max_vel, int margin, float dt) +static void clampBoundsInDomain(SmokeDomainSettings *sds, + int min[3], + int max[3], + float *min_vel, + float *max_vel, + int margin, + float dt) { - int i; - for (i = 0; i < 3; i++) { - int adapt = (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) ? sds->adapt_res : 0; - /* add margin */ - min[i] -= margin; - max[i] += margin; - - /* adapt to velocity */ - if (min_vel && min_vel[i] < 0.0f) { - min[i] += (int)floor(min_vel[i] * dt); - } - if (max_vel && max_vel[i] > 0.0f) { - max[i] += (int)ceil(max_vel[i] * dt); - } - - /* clamp within domain max size */ - CLAMP(min[i], -adapt, sds->base_res[i] + adapt); - CLAMP(max[i], -adapt, sds->base_res[i] + adapt); - } + int i; + for (i = 0; i < 3; i++) { + int adapt = (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) ? sds->adapt_res : 0; + /* add margin */ + min[i] -= margin; + max[i] += margin; + + /* adapt to velocity */ + if (min_vel && min_vel[i] < 0.0f) { + min[i] += (int)floor(min_vel[i] * dt); + } + if (max_vel && max_vel[i] > 0.0f) { + max[i] += (int)ceil(max_vel[i] * dt); + } + + /* clamp within domain max size */ + CLAMP(min[i], -adapt, sds->base_res[i] + adapt); + CLAMP(max[i], -adapt, sds->base_res[i] + adapt); + } } static void em_allocateData(EmissionMap *em, bool use_velocity, int hires_mul) { - int i, res[3]; - - for (i = 0; i < 3; i++) { - res[i] = em->max[i] - em->min[i]; - if (res[i] <= 0) - return; - } - em->total_cells = res[0] * res[1] * res[2]; - copy_v3_v3_int(em->res, res); - - - em->influence = MEM_callocN(sizeof(float) * em->total_cells, "smoke_flow_influence"); - if (use_velocity) - em->velocity = MEM_callocN(sizeof(float) * em->total_cells * 3, "smoke_flow_velocity"); - - /* allocate high resolution map if required */ - if (hires_mul > 1) { - int total_cells_high = em->total_cells * (hires_mul * hires_mul * hires_mul); - - for (i = 0; i < 3; i++) { - em->hmin[i] = em->min[i] * hires_mul; - em->hmax[i] = em->max[i] * hires_mul; - em->hres[i] = em->res[i] * hires_mul; - } - - em->influence_high = MEM_callocN(sizeof(float) * total_cells_high, "smoke_flow_influence_high"); - } - em->valid = 1; + int i, res[3]; + + for (i = 0; i < 3; i++) { + res[i] = em->max[i] - em->min[i]; + if (res[i] <= 0) + return; + } + em->total_cells = res[0] * res[1] * res[2]; + copy_v3_v3_int(em->res, res); + + em->influence = MEM_callocN(sizeof(float) * em->total_cells, "smoke_flow_influence"); + if (use_velocity) + em->velocity = MEM_callocN(sizeof(float) * em->total_cells * 3, "smoke_flow_velocity"); + + /* allocate high resolution map if required */ + if (hires_mul > 1) { + int total_cells_high = em->total_cells * (hires_mul * hires_mul * hires_mul); + + for (i = 0; i < 3; i++) { + em->hmin[i] = em->min[i] * hires_mul; + em->hmax[i] = em->max[i] * hires_mul; + em->hres[i] = em->res[i] * hires_mul; + } + + em->influence_high = MEM_callocN(sizeof(float) * total_cells_high, + "smoke_flow_influence_high"); + } + em->valid = 1; } static void em_freeData(EmissionMap *em) { - if (em->influence) - MEM_freeN(em->influence); - if (em->influence_high) - MEM_freeN(em->influence_high); - if (em->velocity) - MEM_freeN(em->velocity); + if (em->influence) + MEM_freeN(em->influence); + if (em->influence_high) + MEM_freeN(em->influence_high); + if (em->velocity) + MEM_freeN(em->velocity); } -static void em_combineMaps(EmissionMap *output, EmissionMap *em2, int hires_multiplier, int additive, float sample_size) +static void em_combineMaps( + EmissionMap *output, EmissionMap *em2, int hires_multiplier, int additive, float sample_size) { - int i, x, y, z; - - /* copyfill input 1 struct and clear output for new allocation */ - EmissionMap em1; - memcpy(&em1, output, sizeof(EmissionMap)); - memset(output, 0, sizeof(EmissionMap)); - - for (i = 0; i < 3; i++) { - if (em1.valid) { - output->min[i] = MIN2(em1.min[i], em2->min[i]); - output->max[i] = MAX2(em1.max[i], em2->max[i]); - } - else { - output->min[i] = em2->min[i]; - output->max[i] = em2->max[i]; - } - } - /* allocate output map */ - em_allocateData(output, (em1.velocity || em2->velocity), hires_multiplier); - - /* base resolution inputs */ - for (x = output->min[0]; x < output->max[0]; x++) - for (y = output->min[1]; y < output->max[1]; y++) - for (z = output->min[2]; z < output->max[2]; z++) { - int index_out = smoke_get_index(x - output->min[0], output->res[0], y - output->min[1], output->res[1], z - output->min[2]); - - /* initialize with first input if in range */ - if (x >= em1.min[0] && x < em1.max[0] && - y >= em1.min[1] && y < em1.max[1] && - z >= em1.min[2] && z < em1.max[2]) - { - int index_in = smoke_get_index(x - em1.min[0], em1.res[0], y - em1.min[1], em1.res[1], z - em1.min[2]); - - /* values */ - output->influence[index_out] = em1.influence[index_in]; - if (output->velocity && em1.velocity) { - copy_v3_v3(&output->velocity[index_out * 3], &em1.velocity[index_in * 3]); - } - } - - /* apply second input if in range */ - if (x >= em2->min[0] && x < em2->max[0] && - y >= em2->min[1] && y < em2->max[1] && - z >= em2->min[2] && z < em2->max[2]) - { - int index_in = smoke_get_index(x - em2->min[0], em2->res[0], y - em2->min[1], em2->res[1], z - em2->min[2]); - - /* values */ - if (additive) { - output->influence[index_out] += em2->influence[index_in] * sample_size; - } - else { - output->influence[index_out] = MAX2(em2->influence[index_in], output->influence[index_out]); - } - if (output->velocity && em2->velocity) { - /* last sample replaces the velocity */ - output->velocity[index_out * 3] = ADD_IF_LOWER(output->velocity[index_out * 3], em2->velocity[index_in * 3]); - output->velocity[index_out * 3 + 1] = ADD_IF_LOWER(output->velocity[index_out * 3 + 1], em2->velocity[index_in * 3 + 1]); - output->velocity[index_out * 3 + 2] = ADD_IF_LOWER(output->velocity[index_out * 3 + 2], em2->velocity[index_in * 3 + 2]); - } - } - } // low res loop - - - - /* initialize high resolution input if available */ - if (output->influence_high) { - for (x = output->hmin[0]; x < output->hmax[0]; x++) - for (y = output->hmin[1]; y < output->hmax[1]; y++) - for (z = output->hmin[2]; z < output->hmax[2]; z++) { - int index_out = smoke_get_index(x - output->hmin[0], output->hres[0], y - output->hmin[1], output->hres[1], z - output->hmin[2]); - - /* initialize with first input if in range */ - if (x >= em1.hmin[0] && x < em1.hmax[0] && - y >= em1.hmin[1] && y < em1.hmax[1] && - z >= em1.hmin[2] && z < em1.hmax[2]) - { - int index_in = smoke_get_index(x - em1.hmin[0], em1.hres[0], y - em1.hmin[1], em1.hres[1], z - em1.hmin[2]); - /* values */ - output->influence_high[index_out] = em1.influence_high[index_in]; - } - - /* apply second input if in range */ - if (x >= em2->hmin[0] && x < em2->hmax[0] && - y >= em2->hmin[1] && y < em2->hmax[1] && - z >= em2->hmin[2] && z < em2->hmax[2]) - { - int index_in = smoke_get_index(x - em2->hmin[0], em2->hres[0], y - em2->hmin[1], em2->hres[1], z - em2->hmin[2]); - - /* values */ - if (additive) { - output->influence_high[index_out] += em2->influence_high[index_in] * sample_size; - } - else { - output->influence_high[index_out] = MAX2(em2->influence_high[index_in], output->influence_high[index_out]); - } - } - } // high res loop - } - - /* free original data */ - em_freeData(&em1); + int i, x, y, z; + + /* copyfill input 1 struct and clear output for new allocation */ + EmissionMap em1; + memcpy(&em1, output, sizeof(EmissionMap)); + memset(output, 0, sizeof(EmissionMap)); + + for (i = 0; i < 3; i++) { + if (em1.valid) { + output->min[i] = MIN2(em1.min[i], em2->min[i]); + output->max[i] = MAX2(em1.max[i], em2->max[i]); + } + else { + output->min[i] = em2->min[i]; + output->max[i] = em2->max[i]; + } + } + /* allocate output map */ + em_allocateData(output, (em1.velocity || em2->velocity), hires_multiplier); + + /* base resolution inputs */ + for (x = output->min[0]; x < output->max[0]; x++) + for (y = output->min[1]; y < output->max[1]; y++) + for (z = output->min[2]; z < output->max[2]; z++) { + int index_out = smoke_get_index(x - output->min[0], + output->res[0], + y - output->min[1], + output->res[1], + z - output->min[2]); + + /* initialize with first input if in range */ + if (x >= em1.min[0] && x < em1.max[0] && y >= em1.min[1] && y < em1.max[1] && + z >= em1.min[2] && z < em1.max[2]) { + int index_in = smoke_get_index( + x - em1.min[0], em1.res[0], y - em1.min[1], em1.res[1], z - em1.min[2]); + + /* values */ + output->influence[index_out] = em1.influence[index_in]; + if (output->velocity && em1.velocity) { + copy_v3_v3(&output->velocity[index_out * 3], &em1.velocity[index_in * 3]); + } + } + + /* apply second input if in range */ + if (x >= em2->min[0] && x < em2->max[0] && y >= em2->min[1] && y < em2->max[1] && + z >= em2->min[2] && z < em2->max[2]) { + int index_in = smoke_get_index( + x - em2->min[0], em2->res[0], y - em2->min[1], em2->res[1], z - em2->min[2]); + + /* values */ + if (additive) { + output->influence[index_out] += em2->influence[index_in] * sample_size; + } + else { + output->influence[index_out] = MAX2(em2->influence[index_in], + output->influence[index_out]); + } + if (output->velocity && em2->velocity) { + /* last sample replaces the velocity */ + output->velocity[index_out * 3] = ADD_IF_LOWER(output->velocity[index_out * 3], + em2->velocity[index_in * 3]); + output->velocity[index_out * 3 + 1] = ADD_IF_LOWER(output->velocity[index_out * 3 + 1], + em2->velocity[index_in * 3 + 1]); + output->velocity[index_out * 3 + 2] = ADD_IF_LOWER(output->velocity[index_out * 3 + 2], + em2->velocity[index_in * 3 + 2]); + } + } + } // low res loop + + /* initialize high resolution input if available */ + if (output->influence_high) { + for (x = output->hmin[0]; x < output->hmax[0]; x++) + for (y = output->hmin[1]; y < output->hmax[1]; y++) + for (z = output->hmin[2]; z < output->hmax[2]; z++) { + int index_out = smoke_get_index(x - output->hmin[0], + output->hres[0], + y - output->hmin[1], + output->hres[1], + z - output->hmin[2]); + + /* initialize with first input if in range */ + if (x >= em1.hmin[0] && x < em1.hmax[0] && y >= em1.hmin[1] && y < em1.hmax[1] && + z >= em1.hmin[2] && z < em1.hmax[2]) { + int index_in = smoke_get_index( + x - em1.hmin[0], em1.hres[0], y - em1.hmin[1], em1.hres[1], z - em1.hmin[2]); + /* values */ + output->influence_high[index_out] = em1.influence_high[index_in]; + } + + /* apply second input if in range */ + if (x >= em2->hmin[0] && x < em2->hmax[0] && y >= em2->hmin[1] && y < em2->hmax[1] && + z >= em2->hmin[2] && z < em2->hmax[2]) { + int index_in = smoke_get_index( + x - em2->hmin[0], em2->hres[0], y - em2->hmin[1], em2->hres[1], z - em2->hmin[2]); + + /* values */ + if (additive) { + output->influence_high[index_out] += em2->influence_high[index_in] * sample_size; + } + else { + output->influence_high[index_out] = MAX2(em2->influence_high[index_in], + output->influence_high[index_out]); + } + } + } // high res loop + } + + /* free original data */ + em_freeData(&em1); } typedef struct EmitFromParticlesData { - SmokeFlowSettings *sfs; - KDTree_3d *tree; - int hires_multiplier; + SmokeFlowSettings *sfs; + KDTree_3d *tree; + int hires_multiplier; - EmissionMap *em; - float *particle_vel; - float hr; + EmissionMap *em; + float *particle_vel; + float hr; - int *min, *max, *res; + int *min, *max, *res; - float solid; - float smooth; - float hr_smooth; + float solid; + float smooth; + float hr_smooth; } EmitFromParticlesData; -static void emit_from_particles_task_cb( - void *__restrict userdata, - const int z, - const ParallelRangeTLS *__restrict UNUSED(tls)) +static void emit_from_particles_task_cb(void *__restrict userdata, + const int z, + const ParallelRangeTLS *__restrict UNUSED(tls)) { - EmitFromParticlesData *data = userdata; - SmokeFlowSettings *sfs = data->sfs; - EmissionMap *em = data->em; - const int hires_multiplier = data->hires_multiplier; - - for (int x = data->min[0]; x < data->max[0]; x++) { - for (int y = data->min[1]; y < data->max[1]; y++) { - /* take low res samples where possible */ - if (hires_multiplier <= 1 || !(x % hires_multiplier || y % hires_multiplier || z % hires_multiplier)) { - /* get low res space coordinates */ - const int lx = x / hires_multiplier; - const int ly = y / hires_multiplier; - const int lz = z / hires_multiplier; - - const int index = smoke_get_index(lx - em->min[0], em->res[0], ly - em->min[1], em->res[1], lz - em->min[2]); - const float ray_start[3] = {((float)lx) + 0.5f, ((float)ly) + 0.5f, ((float)lz) + 0.5f}; - - /* find particle distance from the kdtree */ - KDTreeNearest_3d nearest; - const float range = data->solid + data->smooth; - BLI_kdtree_3d_find_nearest(data->tree, ray_start, &nearest); - - if (nearest.dist < range) { - em->influence[index] = (nearest.dist < data->solid) ? - 1.0f : (1.0f - (nearest.dist - data->solid) / data->smooth); - /* Uses particle velocity as initial velocity for smoke */ - if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && (sfs->psys->part->phystype != PART_PHYS_NO)) { - madd_v3_v3fl(&em->velocity[index * 3], &data->particle_vel[nearest.index * 3], sfs->vel_multi); - } - } - } - - /* take high res samples if required */ - if (hires_multiplier > 1) { - /* get low res space coordinates */ - const float lx = ((float)x) * data->hr; - const float ly = ((float)y) * data->hr; - const float lz = ((float)z) * data->hr; - - const int index = smoke_get_index( - x - data->min[0], data->res[0], y - data->min[1], data->res[1], z - data->min[2]); - const float ray_start[3] = {lx + 0.5f * data->hr, ly + 0.5f * data->hr, lz + 0.5f * data->hr}; - - /* find particle distance from the kdtree */ - KDTreeNearest_3d nearest; - const float range = data->solid + data->hr_smooth; - BLI_kdtree_3d_find_nearest(data->tree, ray_start, &nearest); - - if (nearest.dist < range) { - em->influence_high[index] = (nearest.dist < data->solid) ? - 1.0f : (1.0f - (nearest.dist - data->solid) / data->smooth); - } - } - - } - } + EmitFromParticlesData *data = userdata; + SmokeFlowSettings *sfs = data->sfs; + EmissionMap *em = data->em; + const int hires_multiplier = data->hires_multiplier; + + for (int x = data->min[0]; x < data->max[0]; x++) { + for (int y = data->min[1]; y < data->max[1]; y++) { + /* take low res samples where possible */ + if (hires_multiplier <= 1 || + !(x % hires_multiplier || y % hires_multiplier || z % hires_multiplier)) { + /* get low res space coordinates */ + const int lx = x / hires_multiplier; + const int ly = y / hires_multiplier; + const int lz = z / hires_multiplier; + + const int index = smoke_get_index( + lx - em->min[0], em->res[0], ly - em->min[1], em->res[1], lz - em->min[2]); + const float ray_start[3] = {((float)lx) + 0.5f, ((float)ly) + 0.5f, ((float)lz) + 0.5f}; + + /* find particle distance from the kdtree */ + KDTreeNearest_3d nearest; + const float range = data->solid + data->smooth; + BLI_kdtree_3d_find_nearest(data->tree, ray_start, &nearest); + + if (nearest.dist < range) { + em->influence[index] = (nearest.dist < data->solid) ? + 1.0f : + (1.0f - (nearest.dist - data->solid) / data->smooth); + /* Uses particle velocity as initial velocity for smoke */ + if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && + (sfs->psys->part->phystype != PART_PHYS_NO)) { + madd_v3_v3fl( + &em->velocity[index * 3], &data->particle_vel[nearest.index * 3], sfs->vel_multi); + } + } + } + + /* take high res samples if required */ + if (hires_multiplier > 1) { + /* get low res space coordinates */ + const float lx = ((float)x) * data->hr; + const float ly = ((float)y) * data->hr; + const float lz = ((float)z) * data->hr; + + const int index = smoke_get_index( + x - data->min[0], data->res[0], y - data->min[1], data->res[1], z - data->min[2]); + const float ray_start[3] = { + lx + 0.5f * data->hr, ly + 0.5f * data->hr, lz + 0.5f * data->hr}; + + /* find particle distance from the kdtree */ + KDTreeNearest_3d nearest; + const float range = data->solid + data->hr_smooth; + BLI_kdtree_3d_find_nearest(data->tree, ray_start, &nearest); + + if (nearest.dist < range) { + em->influence_high[index] = (nearest.dist < data->solid) ? + 1.0f : + (1.0f - (nearest.dist - data->solid) / data->smooth); + } + } + } + } } -static void emit_from_particles( - Object *flow_ob, SmokeDomainSettings *sds, SmokeFlowSettings *sfs, EmissionMap *em, Depsgraph *depsgraph, Scene *scene, float dt) +static void emit_from_particles(Object *flow_ob, + SmokeDomainSettings *sds, + SmokeFlowSettings *sfs, + EmissionMap *em, + Depsgraph *depsgraph, + Scene *scene, + float dt) { - if (sfs && sfs->psys && sfs->psys->part && ELEM(sfs->psys->part->type, PART_EMITTER, PART_FLUID)) // is particle system selected - { - ParticleSimulationData sim; - ParticleSystem *psys = sfs->psys; - float *particle_pos; - float *particle_vel; - int totpart = psys->totpart, totchild; - int p = 0; - int valid_particles = 0; - int bounds_margin = 1; - - /* radius based flow */ - const float solid = sfs->particle_size * 0.5f; - const float smooth = 0.5f; /* add 0.5 cells of linear falloff to reduce aliasing */ - int hires_multiplier = 1; - KDTree_3d *tree = NULL; - - sim.depsgraph = depsgraph; - sim.scene = scene; - sim.ob = flow_ob; - sim.psys = psys; - sim.psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); - - /* prepare curvemapping tables */ - if ((psys->part->child_flag & PART_CHILD_USE_CLUMP_CURVE) && psys->part->clumpcurve) - curvemapping_changed_all(psys->part->clumpcurve); - if ((psys->part->child_flag & PART_CHILD_USE_ROUGH_CURVE) && psys->part->roughcurve) - curvemapping_changed_all(psys->part->roughcurve); - if ((psys->part->child_flag & PART_CHILD_USE_TWIST_CURVE) && psys->part->twistcurve) - curvemapping_changed_all(psys->part->twistcurve); - - /* initialize particle cache */ - if (psys->part->type == PART_HAIR) { - // TODO: PART_HAIR not supported whatsoever - totchild = 0; - } - else { - totchild = psys->totchild * psys->part->disp / 100; - } - - particle_pos = MEM_callocN(sizeof(float) * (totpart + totchild) * 3, "smoke_flow_particles"); - particle_vel = MEM_callocN(sizeof(float) * (totpart + totchild) * 3, "smoke_flow_particles"); - - /* setup particle radius emission if enabled */ - if (sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE) { - tree = BLI_kdtree_3d_new(psys->totpart + psys->totchild); - - /* check need for high resolution map */ - if ((sds->flags & MOD_SMOKE_HIGHRES) && (sds->highres_sampling == SM_HRES_FULLSAMPLE)) { - hires_multiplier = sds->amplify + 1; - } - - bounds_margin = (int)ceil(solid + smooth); - } - - /* calculate local position for each particle */ - for (p = 0; p < totpart + totchild; p++) - { - ParticleKey state; - float *pos; - if (p < totpart) { - if (psys->particles[p].flag & (PARS_NO_DISP | PARS_UNEXIST)) - continue; - } - else { - /* handle child particle */ - ChildParticle *cpa = &psys->child[p - totpart]; - if (psys->particles[cpa->parent].flag & (PARS_NO_DISP | PARS_UNEXIST)) - continue; - } - - state.time = DEG_get_ctime(depsgraph); /* use depsgraph time */ - if (psys_get_particle_state(&sim, p, &state, 0) == 0) - continue; - - /* location */ - pos = &particle_pos[valid_particles * 3]; - copy_v3_v3(pos, state.co); - smoke_pos_to_cell(sds, pos); - - /* velocity */ - copy_v3_v3(&particle_vel[valid_particles * 3], state.vel); - mul_mat3_m4_v3(sds->imat, &particle_vel[valid_particles * 3]); - - if (sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE) { - BLI_kdtree_3d_insert(tree, valid_particles, pos); - } - - /* calculate emission map bounds */ - em_boundInsert(em, pos); - valid_particles++; - } - - /* set emission map */ - clampBoundsInDomain(sds, em->min, em->max, NULL, NULL, bounds_margin, dt); - em_allocateData(em, sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY, hires_multiplier); - - if (!(sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE)) { - for (p = 0; p < valid_particles; p++) - { - int cell[3]; - size_t i = 0; - size_t index = 0; - int badcell = 0; - - /* 1. get corresponding cell */ - cell[0] = floor(particle_pos[p * 3]) - em->min[0]; - cell[1] = floor(particle_pos[p * 3 + 1]) - em->min[1]; - cell[2] = floor(particle_pos[p * 3 + 2]) - em->min[2]; - /* check if cell is valid (in the domain boundary) */ - for (i = 0; i < 3; i++) { - if ((cell[i] > em->res[i] - 1) || (cell[i] < 0)) { - badcell = 1; - break; - } - } - if (badcell) - continue; - /* get cell index */ - index = smoke_get_index(cell[0], em->res[0], cell[1], em->res[1], cell[2]); - /* Add influence to emission map */ - em->influence[index] = 1.0f; - /* Uses particle velocity as initial velocity for smoke */ - if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && (psys->part->phystype != PART_PHYS_NO)) - { - madd_v3_v3fl(&em->velocity[index * 3], &particle_vel[p * 3], sfs->vel_multi); - } - } // particles loop - } - else if (valid_particles > 0) { // MOD_SMOKE_FLOW_USE_PART_SIZE - int min[3], max[3], res[3]; - const float hr = 1.0f / ((float)hires_multiplier); - /* slightly adjust high res antialias smoothness based on number of divisions - * to allow smaller details but yet not differing too much from the low res size */ - const float hr_smooth = smooth * powf(hr, 1.0f / 3.0f); - - /* setup loop bounds */ - for (int i = 0; i < 3; i++) { - min[i] = em->min[i] * hires_multiplier; - max[i] = em->max[i] * hires_multiplier; - res[i] = em->res[i] * hires_multiplier; - } - - BLI_kdtree_3d_balance(tree); - - EmitFromParticlesData data = { - .sfs = sfs, .tree = tree, .hires_multiplier = hires_multiplier, .hr = hr, - .em = em, .particle_vel = particle_vel, .min = min, .max = max, .res = res, - .solid = solid, .smooth = smooth, .hr_smooth = hr_smooth, - }; - - ParallelRangeSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC; - BLI_task_parallel_range(min[2], max[2], - &data, - emit_from_particles_task_cb, - &settings); - } - - if (sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE) { - BLI_kdtree_3d_free(tree); - } - - /* free data */ - if (particle_pos) - MEM_freeN(particle_pos); - if (particle_vel) - MEM_freeN(particle_vel); - } + if (sfs && sfs->psys && sfs->psys->part && + ELEM(sfs->psys->part->type, PART_EMITTER, PART_FLUID)) // is particle system selected + { + ParticleSimulationData sim; + ParticleSystem *psys = sfs->psys; + float *particle_pos; + float *particle_vel; + int totpart = psys->totpart, totchild; + int p = 0; + int valid_particles = 0; + int bounds_margin = 1; + + /* radius based flow */ + const float solid = sfs->particle_size * 0.5f; + const float smooth = 0.5f; /* add 0.5 cells of linear falloff to reduce aliasing */ + int hires_multiplier = 1; + KDTree_3d *tree = NULL; + + sim.depsgraph = depsgraph; + sim.scene = scene; + sim.ob = flow_ob; + sim.psys = psys; + sim.psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); + + /* prepare curvemapping tables */ + if ((psys->part->child_flag & PART_CHILD_USE_CLUMP_CURVE) && psys->part->clumpcurve) + curvemapping_changed_all(psys->part->clumpcurve); + if ((psys->part->child_flag & PART_CHILD_USE_ROUGH_CURVE) && psys->part->roughcurve) + curvemapping_changed_all(psys->part->roughcurve); + if ((psys->part->child_flag & PART_CHILD_USE_TWIST_CURVE) && psys->part->twistcurve) + curvemapping_changed_all(psys->part->twistcurve); + + /* initialize particle cache */ + if (psys->part->type == PART_HAIR) { + // TODO: PART_HAIR not supported whatsoever + totchild = 0; + } + else { + totchild = psys->totchild * psys->part->disp / 100; + } + + particle_pos = MEM_callocN(sizeof(float) * (totpart + totchild) * 3, "smoke_flow_particles"); + particle_vel = MEM_callocN(sizeof(float) * (totpart + totchild) * 3, "smoke_flow_particles"); + + /* setup particle radius emission if enabled */ + if (sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE) { + tree = BLI_kdtree_3d_new(psys->totpart + psys->totchild); + + /* check need for high resolution map */ + if ((sds->flags & MOD_SMOKE_HIGHRES) && (sds->highres_sampling == SM_HRES_FULLSAMPLE)) { + hires_multiplier = sds->amplify + 1; + } + + bounds_margin = (int)ceil(solid + smooth); + } + + /* calculate local position for each particle */ + for (p = 0; p < totpart + totchild; p++) { + ParticleKey state; + float *pos; + if (p < totpart) { + if (psys->particles[p].flag & (PARS_NO_DISP | PARS_UNEXIST)) + continue; + } + else { + /* handle child particle */ + ChildParticle *cpa = &psys->child[p - totpart]; + if (psys->particles[cpa->parent].flag & (PARS_NO_DISP | PARS_UNEXIST)) + continue; + } + + state.time = DEG_get_ctime(depsgraph); /* use depsgraph time */ + if (psys_get_particle_state(&sim, p, &state, 0) == 0) + continue; + + /* location */ + pos = &particle_pos[valid_particles * 3]; + copy_v3_v3(pos, state.co); + smoke_pos_to_cell(sds, pos); + + /* velocity */ + copy_v3_v3(&particle_vel[valid_particles * 3], state.vel); + mul_mat3_m4_v3(sds->imat, &particle_vel[valid_particles * 3]); + + if (sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE) { + BLI_kdtree_3d_insert(tree, valid_particles, pos); + } + + /* calculate emission map bounds */ + em_boundInsert(em, pos); + valid_particles++; + } + + /* set emission map */ + clampBoundsInDomain(sds, em->min, em->max, NULL, NULL, bounds_margin, dt); + em_allocateData(em, sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY, hires_multiplier); + + if (!(sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE)) { + for (p = 0; p < valid_particles; p++) { + int cell[3]; + size_t i = 0; + size_t index = 0; + int badcell = 0; + + /* 1. get corresponding cell */ + cell[0] = floor(particle_pos[p * 3]) - em->min[0]; + cell[1] = floor(particle_pos[p * 3 + 1]) - em->min[1]; + cell[2] = floor(particle_pos[p * 3 + 2]) - em->min[2]; + /* check if cell is valid (in the domain boundary) */ + for (i = 0; i < 3; i++) { + if ((cell[i] > em->res[i] - 1) || (cell[i] < 0)) { + badcell = 1; + break; + } + } + if (badcell) + continue; + /* get cell index */ + index = smoke_get_index(cell[0], em->res[0], cell[1], em->res[1], cell[2]); + /* Add influence to emission map */ + em->influence[index] = 1.0f; + /* Uses particle velocity as initial velocity for smoke */ + if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && (psys->part->phystype != PART_PHYS_NO)) { + madd_v3_v3fl(&em->velocity[index * 3], &particle_vel[p * 3], sfs->vel_multi); + } + } // particles loop + } + else if (valid_particles > 0) { // MOD_SMOKE_FLOW_USE_PART_SIZE + int min[3], max[3], res[3]; + const float hr = 1.0f / ((float)hires_multiplier); + /* slightly adjust high res antialias smoothness based on number of divisions + * to allow smaller details but yet not differing too much from the low res size */ + const float hr_smooth = smooth * powf(hr, 1.0f / 3.0f); + + /* setup loop bounds */ + for (int i = 0; i < 3; i++) { + min[i] = em->min[i] * hires_multiplier; + max[i] = em->max[i] * hires_multiplier; + res[i] = em->res[i] * hires_multiplier; + } + + BLI_kdtree_3d_balance(tree); + + EmitFromParticlesData data = { + .sfs = sfs, + .tree = tree, + .hires_multiplier = hires_multiplier, + .hr = hr, + .em = em, + .particle_vel = particle_vel, + .min = min, + .max = max, + .res = res, + .solid = solid, + .smooth = smooth, + .hr_smooth = hr_smooth, + }; + + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC; + BLI_task_parallel_range(min[2], max[2], &data, emit_from_particles_task_cb, &settings); + } + + if (sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE) { + BLI_kdtree_3d_free(tree); + } + + /* free data */ + if (particle_pos) + MEM_freeN(particle_pos); + if (particle_vel) + MEM_freeN(particle_vel); + } } -static void sample_mesh( - SmokeFlowSettings *sfs, - const MVert *mvert, const MLoop *mloop, const MLoopTri *mlooptri, const MLoopUV *mloopuv, - float *influence_map, float *velocity_map, int index, const int base_res[3], float flow_center[3], - BVHTreeFromMesh *treeData, const float ray_start[3], const float *vert_vel, - bool has_velocity, int defgrp_index, MDeformVert *dvert, - float x, float y, float z) +static void sample_mesh(SmokeFlowSettings *sfs, + const MVert *mvert, + const MLoop *mloop, + const MLoopTri *mlooptri, + const MLoopUV *mloopuv, + float *influence_map, + float *velocity_map, + int index, + const int base_res[3], + float flow_center[3], + BVHTreeFromMesh *treeData, + const float ray_start[3], + const float *vert_vel, + bool has_velocity, + int defgrp_index, + MDeformVert *dvert, + float x, + float y, + float z) { - float ray_dir[3] = {1.0f, 0.0f, 0.0f}; - BVHTreeRayHit hit = {0}; - BVHTreeNearest nearest = {0}; - - float volume_factor = 0.0f; - float sample_str = 0.0f; - - hit.index = -1; - hit.dist = 9999; - nearest.index = -1; - nearest.dist_sq = sfs->surface_distance * sfs->surface_distance; /* find_nearest uses squared distance */ - - /* Check volume collision */ - if (sfs->volume_density) { - if (BLI_bvhtree_ray_cast(treeData->tree, ray_start, ray_dir, 0.0f, &hit, treeData->raycast_callback, treeData) != -1) { - float dot = ray_dir[0] * hit.no[0] + ray_dir[1] * hit.no[1] + ray_dir[2] * hit.no[2]; - /* If ray and hit face normal are facing same direction - * hit point is inside a closed mesh. */ - if (dot >= 0) { - /* Also cast a ray in opposite direction to make sure - * point is at least surrounded by two faces */ - negate_v3(ray_dir); - hit.index = -1; - hit.dist = 9999; - - BLI_bvhtree_ray_cast(treeData->tree, ray_start, ray_dir, 0.0f, &hit, treeData->raycast_callback, treeData); - if (hit.index != -1) { - volume_factor = sfs->volume_density; - } - } - } - } - - /* find the nearest point on the mesh */ - if (BLI_bvhtree_find_nearest(treeData->tree, ray_start, &nearest, treeData->nearest_callback, treeData) != -1) { - float weights[3]; - int v1, v2, v3, f_index = nearest.index; - float n1[3], n2[3], n3[3], hit_normal[3]; - - /* emit from surface based on distance */ - if (sfs->surface_distance) { - sample_str = sqrtf(nearest.dist_sq) / sfs->surface_distance; - CLAMP(sample_str, 0.0f, 1.0f); - sample_str = pow(1.0f - sample_str, 0.5f); - } - else - sample_str = 0.0f; - - /* calculate barycentric weights for nearest point */ - v1 = mloop[mlooptri[f_index].tri[0]].v; - v2 = mloop[mlooptri[f_index].tri[1]].v; - v3 = mloop[mlooptri[f_index].tri[2]].v; - interp_weights_tri_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, nearest.co); - - if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && velocity_map) { - /* apply normal directional velocity */ - if (sfs->vel_normal) { - /* interpolate vertex normal vectors to get nearest point normal */ - normal_short_to_float_v3(n1, mvert[v1].no); - normal_short_to_float_v3(n2, mvert[v2].no); - normal_short_to_float_v3(n3, mvert[v3].no); - interp_v3_v3v3v3(hit_normal, n1, n2, n3, weights); - normalize_v3(hit_normal); - /* apply normal directional and random velocity - * - TODO: random disabled for now since it doesn't really work well as pressure calc smoothens it out... */ - velocity_map[index * 3] += hit_normal[0] * sfs->vel_normal * 0.25f; - velocity_map[index * 3 + 1] += hit_normal[1] * sfs->vel_normal * 0.25f; - velocity_map[index * 3 + 2] += hit_normal[2] * sfs->vel_normal * 0.25f; - /* TODO: for fire emitted from mesh surface we can use - * Vf = Vs + (Ps/Pf - 1)*S to model gaseous expansion from solid to fuel */ - } - /* apply object velocity */ - if (has_velocity && sfs->vel_multi) { - float hit_vel[3]; - interp_v3_v3v3v3(hit_vel, &vert_vel[v1 * 3], &vert_vel[v2 * 3], &vert_vel[v3 * 3], weights); - velocity_map[index * 3] += hit_vel[0] * sfs->vel_multi; - velocity_map[index * 3 + 1] += hit_vel[1] * sfs->vel_multi; - velocity_map[index * 3 + 2] += hit_vel[2] * sfs->vel_multi; - } - } - - /* apply vertex group influence if used */ - if (defgrp_index != -1 && dvert) { - float weight_mask = defvert_find_weight(&dvert[v1], defgrp_index) * weights[0] + - defvert_find_weight(&dvert[v2], defgrp_index) * weights[1] + - defvert_find_weight(&dvert[v3], defgrp_index) * weights[2]; - sample_str *= weight_mask; - } - - /* apply emission texture */ - if ((sfs->flags & MOD_SMOKE_FLOW_TEXTUREEMIT) && sfs->noise_texture) { - float tex_co[3] = {0}; - TexResult texres; - - if (sfs->texture_type == MOD_SMOKE_FLOW_TEXTURE_MAP_AUTO) { - tex_co[0] = ((x - flow_center[0]) / base_res[0]) / sfs->texture_size; - tex_co[1] = ((y - flow_center[1]) / base_res[1]) / sfs->texture_size; - tex_co[2] = ((z - flow_center[2]) / base_res[2] - sfs->texture_offset) / sfs->texture_size; - } - else if (mloopuv) { - const float *uv[3]; - uv[0] = mloopuv[mlooptri[f_index].tri[0]].uv; - uv[1] = mloopuv[mlooptri[f_index].tri[1]].uv; - uv[2] = mloopuv[mlooptri[f_index].tri[2]].uv; - - interp_v2_v2v2v2(tex_co, UNPACK3(uv), weights); - - /* map between -1.0f and 1.0f */ - tex_co[0] = tex_co[0] * 2.0f - 1.0f; - tex_co[1] = tex_co[1] * 2.0f - 1.0f; - tex_co[2] = sfs->texture_offset; - } - texres.nor = NULL; - BKE_texture_get_value(NULL, sfs->noise_texture, tex_co, &texres, false); - sample_str *= texres.tin; - } - } - - /* multiply initial velocity by emitter influence */ - if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && velocity_map) { - mul_v3_fl(&velocity_map[index * 3], sample_str); - } - - /* apply final influence based on volume factor */ - influence_map[index] = MAX2(volume_factor, sample_str); + float ray_dir[3] = {1.0f, 0.0f, 0.0f}; + BVHTreeRayHit hit = {0}; + BVHTreeNearest nearest = {0}; + + float volume_factor = 0.0f; + float sample_str = 0.0f; + + hit.index = -1; + hit.dist = 9999; + nearest.index = -1; + nearest.dist_sq = sfs->surface_distance * + sfs->surface_distance; /* find_nearest uses squared distance */ + + /* Check volume collision */ + if (sfs->volume_density) { + if (BLI_bvhtree_ray_cast(treeData->tree, + ray_start, + ray_dir, + 0.0f, + &hit, + treeData->raycast_callback, + treeData) != -1) { + float dot = ray_dir[0] * hit.no[0] + ray_dir[1] * hit.no[1] + ray_dir[2] * hit.no[2]; + /* If ray and hit face normal are facing same direction + * hit point is inside a closed mesh. */ + if (dot >= 0) { + /* Also cast a ray in opposite direction to make sure + * point is at least surrounded by two faces */ + negate_v3(ray_dir); + hit.index = -1; + hit.dist = 9999; + + BLI_bvhtree_ray_cast( + treeData->tree, ray_start, ray_dir, 0.0f, &hit, treeData->raycast_callback, treeData); + if (hit.index != -1) { + volume_factor = sfs->volume_density; + } + } + } + } + + /* find the nearest point on the mesh */ + if (BLI_bvhtree_find_nearest( + treeData->tree, ray_start, &nearest, treeData->nearest_callback, treeData) != -1) { + float weights[3]; + int v1, v2, v3, f_index = nearest.index; + float n1[3], n2[3], n3[3], hit_normal[3]; + + /* emit from surface based on distance */ + if (sfs->surface_distance) { + sample_str = sqrtf(nearest.dist_sq) / sfs->surface_distance; + CLAMP(sample_str, 0.0f, 1.0f); + sample_str = pow(1.0f - sample_str, 0.5f); + } + else + sample_str = 0.0f; + + /* calculate barycentric weights for nearest point */ + v1 = mloop[mlooptri[f_index].tri[0]].v; + v2 = mloop[mlooptri[f_index].tri[1]].v; + v3 = mloop[mlooptri[f_index].tri[2]].v; + interp_weights_tri_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, nearest.co); + + if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && velocity_map) { + /* apply normal directional velocity */ + if (sfs->vel_normal) { + /* interpolate vertex normal vectors to get nearest point normal */ + normal_short_to_float_v3(n1, mvert[v1].no); + normal_short_to_float_v3(n2, mvert[v2].no); + normal_short_to_float_v3(n3, mvert[v3].no); + interp_v3_v3v3v3(hit_normal, n1, n2, n3, weights); + normalize_v3(hit_normal); + /* apply normal directional and random velocity + * - TODO: random disabled for now since it doesn't really work well as pressure calc smoothens it out... */ + velocity_map[index * 3] += hit_normal[0] * sfs->vel_normal * 0.25f; + velocity_map[index * 3 + 1] += hit_normal[1] * sfs->vel_normal * 0.25f; + velocity_map[index * 3 + 2] += hit_normal[2] * sfs->vel_normal * 0.25f; + /* TODO: for fire emitted from mesh surface we can use + * Vf = Vs + (Ps/Pf - 1)*S to model gaseous expansion from solid to fuel */ + } + /* apply object velocity */ + if (has_velocity && sfs->vel_multi) { + float hit_vel[3]; + interp_v3_v3v3v3( + hit_vel, &vert_vel[v1 * 3], &vert_vel[v2 * 3], &vert_vel[v3 * 3], weights); + velocity_map[index * 3] += hit_vel[0] * sfs->vel_multi; + velocity_map[index * 3 + 1] += hit_vel[1] * sfs->vel_multi; + velocity_map[index * 3 + 2] += hit_vel[2] * sfs->vel_multi; + } + } + + /* apply vertex group influence if used */ + if (defgrp_index != -1 && dvert) { + float weight_mask = defvert_find_weight(&dvert[v1], defgrp_index) * weights[0] + + defvert_find_weight(&dvert[v2], defgrp_index) * weights[1] + + defvert_find_weight(&dvert[v3], defgrp_index) * weights[2]; + sample_str *= weight_mask; + } + + /* apply emission texture */ + if ((sfs->flags & MOD_SMOKE_FLOW_TEXTUREEMIT) && sfs->noise_texture) { + float tex_co[3] = {0}; + TexResult texres; + + if (sfs->texture_type == MOD_SMOKE_FLOW_TEXTURE_MAP_AUTO) { + tex_co[0] = ((x - flow_center[0]) / base_res[0]) / sfs->texture_size; + tex_co[1] = ((y - flow_center[1]) / base_res[1]) / sfs->texture_size; + tex_co[2] = ((z - flow_center[2]) / base_res[2] - sfs->texture_offset) / sfs->texture_size; + } + else if (mloopuv) { + const float *uv[3]; + uv[0] = mloopuv[mlooptri[f_index].tri[0]].uv; + uv[1] = mloopuv[mlooptri[f_index].tri[1]].uv; + uv[2] = mloopuv[mlooptri[f_index].tri[2]].uv; + + interp_v2_v2v2v2(tex_co, UNPACK3(uv), weights); + + /* map between -1.0f and 1.0f */ + tex_co[0] = tex_co[0] * 2.0f - 1.0f; + tex_co[1] = tex_co[1] * 2.0f - 1.0f; + tex_co[2] = sfs->texture_offset; + } + texres.nor = NULL; + BKE_texture_get_value(NULL, sfs->noise_texture, tex_co, &texres, false); + sample_str *= texres.tin; + } + } + + /* multiply initial velocity by emitter influence */ + if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && velocity_map) { + mul_v3_fl(&velocity_map[index * 3], sample_str); + } + + /* apply final influence based on volume factor */ + influence_map[index] = MAX2(volume_factor, sample_str); } typedef struct EmitFromDMData { - SmokeDomainSettings *sds; - SmokeFlowSettings *sfs; - const MVert *mvert; - const MLoop *mloop; - const MLoopTri *mlooptri; - const MLoopUV *mloopuv; - MDeformVert *dvert; - int defgrp_index; - - BVHTreeFromMesh *tree; - int hires_multiplier; - float hr; - - EmissionMap *em; - bool has_velocity; - float *vert_vel; - - float *flow_center; - int *min, *max, *res; + SmokeDomainSettings *sds; + SmokeFlowSettings *sfs; + const MVert *mvert; + const MLoop *mloop; + const MLoopTri *mlooptri; + const MLoopUV *mloopuv; + MDeformVert *dvert; + int defgrp_index; + + BVHTreeFromMesh *tree; + int hires_multiplier; + float hr; + + EmissionMap *em; + bool has_velocity; + float *vert_vel; + + float *flow_center; + int *min, *max, *res; } EmitFromDMData; -static void emit_from_mesh_task_cb( - void *__restrict userdata, - const int z, - const ParallelRangeTLS *__restrict UNUSED(tls)) +static void emit_from_mesh_task_cb(void *__restrict userdata, + const int z, + const ParallelRangeTLS *__restrict UNUSED(tls)) { - EmitFromDMData *data = userdata; - EmissionMap *em = data->em; - const int hires_multiplier = data->hires_multiplier; - - for (int x = data->min[0]; x < data->max[0]; x++) { - for (int y = data->min[1]; y < data->max[1]; y++) { - /* take low res samples where possible */ - if (hires_multiplier <= 1 || !(x % hires_multiplier || y % hires_multiplier || z % hires_multiplier)) { - /* get low res space coordinates */ - const int lx = x / hires_multiplier; - const int ly = y / hires_multiplier; - const int lz = z / hires_multiplier; - - const int index = smoke_get_index( - lx - em->min[0], em->res[0], ly - em->min[1], em->res[1], lz - em->min[2]); - const float ray_start[3] = {((float)lx) + 0.5f, ((float)ly) + 0.5f, ((float)lz) + 0.5f}; - - sample_mesh( - data->sfs, data->mvert, data->mloop, data->mlooptri, data->mloopuv, - em->influence, em->velocity, index, data->sds->base_res, data->flow_center, - data->tree, ray_start, data->vert_vel, data->has_velocity, data->defgrp_index, data->dvert, - (float)lx, (float)ly, (float)lz); - } - - /* take high res samples if required */ - if (hires_multiplier > 1) { - /* get low res space coordinates */ - const float lx = ((float)x) * data->hr; - const float ly = ((float)y) * data->hr; - const float lz = ((float)z) * data->hr; - - const int index = smoke_get_index( - x - data->min[0], data->res[0], y - data->min[1], data->res[1], z - data->min[2]); - const float ray_start[3] = {lx + 0.5f * data->hr, ly + 0.5f * data->hr, lz + 0.5f * data->hr}; - - sample_mesh( - data->sfs, data->mvert, data->mloop, data->mlooptri, data->mloopuv, - em->influence_high, NULL, index, data->sds->base_res, data->flow_center, - data->tree, ray_start, data->vert_vel, data->has_velocity, data->defgrp_index, data->dvert, - /* x,y,z needs to be always lowres */ - lx, ly, lz); - } - } - } + EmitFromDMData *data = userdata; + EmissionMap *em = data->em; + const int hires_multiplier = data->hires_multiplier; + + for (int x = data->min[0]; x < data->max[0]; x++) { + for (int y = data->min[1]; y < data->max[1]; y++) { + /* take low res samples where possible */ + if (hires_multiplier <= 1 || + !(x % hires_multiplier || y % hires_multiplier || z % hires_multiplier)) { + /* get low res space coordinates */ + const int lx = x / hires_multiplier; + const int ly = y / hires_multiplier; + const int lz = z / hires_multiplier; + + const int index = smoke_get_index( + lx - em->min[0], em->res[0], ly - em->min[1], em->res[1], lz - em->min[2]); + const float ray_start[3] = {((float)lx) + 0.5f, ((float)ly) + 0.5f, ((float)lz) + 0.5f}; + + sample_mesh(data->sfs, + data->mvert, + data->mloop, + data->mlooptri, + data->mloopuv, + em->influence, + em->velocity, + index, + data->sds->base_res, + data->flow_center, + data->tree, + ray_start, + data->vert_vel, + data->has_velocity, + data->defgrp_index, + data->dvert, + (float)lx, + (float)ly, + (float)lz); + } + + /* take high res samples if required */ + if (hires_multiplier > 1) { + /* get low res space coordinates */ + const float lx = ((float)x) * data->hr; + const float ly = ((float)y) * data->hr; + const float lz = ((float)z) * data->hr; + + const int index = smoke_get_index( + x - data->min[0], data->res[0], y - data->min[1], data->res[1], z - data->min[2]); + const float ray_start[3] = { + lx + 0.5f * data->hr, ly + 0.5f * data->hr, lz + 0.5f * data->hr}; + + sample_mesh(data->sfs, + data->mvert, + data->mloop, + data->mlooptri, + data->mloopuv, + em->influence_high, + NULL, + index, + data->sds->base_res, + data->flow_center, + data->tree, + ray_start, + data->vert_vel, + data->has_velocity, + data->defgrp_index, + data->dvert, + /* x,y,z needs to be always lowres */ + lx, + ly, + lz); + } + } + } } -static void emit_from_mesh(Object *flow_ob, SmokeDomainSettings *sds, SmokeFlowSettings *sfs, EmissionMap *em, float dt) +static void emit_from_mesh( + Object *flow_ob, SmokeDomainSettings *sds, SmokeFlowSettings *sfs, EmissionMap *em, float dt) { - if (sfs->mesh) { - Mesh *me; - int defgrp_index = sfs->vgroup_density - 1; - MDeformVert *dvert = NULL; - MVert *mvert = NULL; - const MLoopTri *mlooptri = NULL; - const MLoopUV *mloopuv = NULL; - const MLoop *mloop = NULL; - BVHTreeFromMesh treeData = {NULL}; - int numOfVerts, i; - float flow_center[3] = {0}; - - float *vert_vel = NULL; - int has_velocity = 0; - int min[3], max[3], res[3]; - int hires_multiplier = 1; - - /* copy mesh for thread safety because we modify it, - * main issue is its VertArray being modified, then replaced and freed - */ - me = BKE_mesh_copy_for_eval(sfs->mesh, true); - - /* Duplicate vertices to modify. */ - if (me->mvert) { - me->mvert = MEM_dupallocN(me->mvert); - CustomData_set_layer(&me->vdata, CD_MVERT, me->mvert); - } - - BKE_mesh_ensure_normals(me); - mvert = me->mvert; - numOfVerts = me->totvert; - dvert = CustomData_get_layer(&me->vdata, CD_MDEFORMVERT); - mloopuv = CustomData_get_layer_named(&me->ldata, CD_MLOOPUV, sfs->uvlayer_name); - mloop = me->mloop; - mlooptri = BKE_mesh_runtime_looptri_ensure(me); - - if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY) { - vert_vel = MEM_callocN(sizeof(float) * numOfVerts * 3, "smoke_flow_velocity"); - - if (sfs->numverts != numOfVerts || !sfs->verts_old) { - if (sfs->verts_old) MEM_freeN(sfs->verts_old); - sfs->verts_old = MEM_callocN(sizeof(float) * numOfVerts * 3, "smoke_flow_verts_old"); - sfs->numverts = numOfVerts; - } - else { - has_velocity = 1; - } - } - - /* Transform mesh vertices to - * domain grid space for fast lookups */ - for (i = 0; i < numOfVerts; i++) { - float n[3]; - /* vert pos */ - mul_m4_v3(flow_ob->obmat, mvert[i].co); - smoke_pos_to_cell(sds, mvert[i].co); - /* vert normal */ - normal_short_to_float_v3(n, mvert[i].no); - mul_mat3_m4_v3(flow_ob->obmat, n); - mul_mat3_m4_v3(sds->imat, n); - normalize_v3(n); - normal_float_to_short_v3(mvert[i].no, n); - /* vert velocity */ - if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY) { - float co[3]; - add_v3fl_v3fl_v3i(co, mvert[i].co, sds->shift); - if (has_velocity) { - sub_v3_v3v3(&vert_vel[i * 3], co, &sfs->verts_old[i * 3]); - mul_v3_fl(&vert_vel[i * 3], sds->dx / dt); - } - copy_v3_v3(&sfs->verts_old[i * 3], co); - } - - /* calculate emission map bounds */ - em_boundInsert(em, mvert[i].co); - } - mul_m4_v3(flow_ob->obmat, flow_center); - smoke_pos_to_cell(sds, flow_center); - - /* check need for high resolution map */ - if ((sds->flags & MOD_SMOKE_HIGHRES) && (sds->highres_sampling == SM_HRES_FULLSAMPLE)) { - hires_multiplier = sds->amplify + 1; - } - - /* set emission map */ - clampBoundsInDomain(sds, em->min, em->max, NULL, NULL, (int)ceil(sfs->surface_distance), dt); - em_allocateData(em, sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY, hires_multiplier); - - /* setup loop bounds */ - for (i = 0; i < 3; i++) { - min[i] = em->min[i] * hires_multiplier; - max[i] = em->max[i] * hires_multiplier; - res[i] = em->res[i] * hires_multiplier; - } - - if (BKE_bvhtree_from_mesh_get(&treeData, me, BVHTREE_FROM_LOOPTRI, 4)) { - const float hr = 1.0f / ((float)hires_multiplier); - - EmitFromDMData data = { - .sds = sds, .sfs = sfs, - .mvert = mvert, .mloop = mloop, .mlooptri = mlooptri, .mloopuv = mloopuv, - .dvert = dvert, .defgrp_index = defgrp_index, - .tree = &treeData, .hires_multiplier = hires_multiplier, .hr = hr, - .em = em, .has_velocity = has_velocity, .vert_vel = vert_vel, - .flow_center = flow_center, .min = min, .max = max, .res = res, - }; - - ParallelRangeSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC; - BLI_task_parallel_range(min[2], max[2], - &data, - emit_from_mesh_task_cb, - &settings); - } - /* free bvh tree */ - free_bvhtree_from_mesh(&treeData); - - if (vert_vel) { - MEM_freeN(vert_vel); - } - - if (me->mvert) { - MEM_freeN(me->mvert); - } - BKE_id_free(NULL, me); - } + if (sfs->mesh) { + Mesh *me; + int defgrp_index = sfs->vgroup_density - 1; + MDeformVert *dvert = NULL; + MVert *mvert = NULL; + const MLoopTri *mlooptri = NULL; + const MLoopUV *mloopuv = NULL; + const MLoop *mloop = NULL; + BVHTreeFromMesh treeData = {NULL}; + int numOfVerts, i; + float flow_center[3] = {0}; + + float *vert_vel = NULL; + int has_velocity = 0; + int min[3], max[3], res[3]; + int hires_multiplier = 1; + + /* copy mesh for thread safety because we modify it, + * main issue is its VertArray being modified, then replaced and freed + */ + me = BKE_mesh_copy_for_eval(sfs->mesh, true); + + /* Duplicate vertices to modify. */ + if (me->mvert) { + me->mvert = MEM_dupallocN(me->mvert); + CustomData_set_layer(&me->vdata, CD_MVERT, me->mvert); + } + + BKE_mesh_ensure_normals(me); + mvert = me->mvert; + numOfVerts = me->totvert; + dvert = CustomData_get_layer(&me->vdata, CD_MDEFORMVERT); + mloopuv = CustomData_get_layer_named(&me->ldata, CD_MLOOPUV, sfs->uvlayer_name); + mloop = me->mloop; + mlooptri = BKE_mesh_runtime_looptri_ensure(me); + + if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY) { + vert_vel = MEM_callocN(sizeof(float) * numOfVerts * 3, "smoke_flow_velocity"); + + if (sfs->numverts != numOfVerts || !sfs->verts_old) { + if (sfs->verts_old) + MEM_freeN(sfs->verts_old); + sfs->verts_old = MEM_callocN(sizeof(float) * numOfVerts * 3, "smoke_flow_verts_old"); + sfs->numverts = numOfVerts; + } + else { + has_velocity = 1; + } + } + + /* Transform mesh vertices to + * domain grid space for fast lookups */ + for (i = 0; i < numOfVerts; i++) { + float n[3]; + /* vert pos */ + mul_m4_v3(flow_ob->obmat, mvert[i].co); + smoke_pos_to_cell(sds, mvert[i].co); + /* vert normal */ + normal_short_to_float_v3(n, mvert[i].no); + mul_mat3_m4_v3(flow_ob->obmat, n); + mul_mat3_m4_v3(sds->imat, n); + normalize_v3(n); + normal_float_to_short_v3(mvert[i].no, n); + /* vert velocity */ + if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY) { + float co[3]; + add_v3fl_v3fl_v3i(co, mvert[i].co, sds->shift); + if (has_velocity) { + sub_v3_v3v3(&vert_vel[i * 3], co, &sfs->verts_old[i * 3]); + mul_v3_fl(&vert_vel[i * 3], sds->dx / dt); + } + copy_v3_v3(&sfs->verts_old[i * 3], co); + } + + /* calculate emission map bounds */ + em_boundInsert(em, mvert[i].co); + } + mul_m4_v3(flow_ob->obmat, flow_center); + smoke_pos_to_cell(sds, flow_center); + + /* check need for high resolution map */ + if ((sds->flags & MOD_SMOKE_HIGHRES) && (sds->highres_sampling == SM_HRES_FULLSAMPLE)) { + hires_multiplier = sds->amplify + 1; + } + + /* set emission map */ + clampBoundsInDomain(sds, em->min, em->max, NULL, NULL, (int)ceil(sfs->surface_distance), dt); + em_allocateData(em, sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY, hires_multiplier); + + /* setup loop bounds */ + for (i = 0; i < 3; i++) { + min[i] = em->min[i] * hires_multiplier; + max[i] = em->max[i] * hires_multiplier; + res[i] = em->res[i] * hires_multiplier; + } + + if (BKE_bvhtree_from_mesh_get(&treeData, me, BVHTREE_FROM_LOOPTRI, 4)) { + const float hr = 1.0f / ((float)hires_multiplier); + + EmitFromDMData data = { + .sds = sds, + .sfs = sfs, + .mvert = mvert, + .mloop = mloop, + .mlooptri = mlooptri, + .mloopuv = mloopuv, + .dvert = dvert, + .defgrp_index = defgrp_index, + .tree = &treeData, + .hires_multiplier = hires_multiplier, + .hr = hr, + .em = em, + .has_velocity = has_velocity, + .vert_vel = vert_vel, + .flow_center = flow_center, + .min = min, + .max = max, + .res = res, + }; + + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC; + BLI_task_parallel_range(min[2], max[2], &data, emit_from_mesh_task_cb, &settings); + } + /* free bvh tree */ + free_bvhtree_from_mesh(&treeData); + + if (vert_vel) { + MEM_freeN(vert_vel); + } + + if (me->mvert) { + MEM_freeN(me->mvert); + } + BKE_id_free(NULL, me); + } } /********************************************************** * Smoke step **********************************************************/ -static void adjustDomainResolution(SmokeDomainSettings *sds, int new_shift[3], EmissionMap *emaps, unsigned int numflowobj, float dt) +static void adjustDomainResolution(SmokeDomainSettings *sds, + int new_shift[3], + EmissionMap *emaps, + unsigned int numflowobj, + float dt) { - const int block_size = sds->amplify + 1; - int min[3] = {32767, 32767, 32767}, max[3] = {-32767, -32767, -32767}, res[3]; - int total_cells = 1, res_changed = 0, shift_changed = 0; - float min_vel[3], max_vel[3]; - int x, y, z; - float *density = smoke_get_density(sds->fluid); - float *fuel = smoke_get_fuel(sds->fluid); - float *bigdensity = smoke_turbulence_get_density(sds->wt); - float *bigfuel = smoke_turbulence_get_fuel(sds->wt); - float *vx = smoke_get_velocity_x(sds->fluid); - float *vy = smoke_get_velocity_y(sds->fluid); - float *vz = smoke_get_velocity_z(sds->fluid); - int wt_res[3]; - - if (sds->flags & MOD_SMOKE_HIGHRES && sds->wt) { - smoke_turbulence_get_res(sds->wt, wt_res); - } - - INIT_MINMAX(min_vel, max_vel); - - /* Calculate bounds for current domain content */ - for (x = sds->res_min[0]; x < sds->res_max[0]; x++) - for (y = sds->res_min[1]; y < sds->res_max[1]; y++) - for (z = sds->res_min[2]; z < sds->res_max[2]; z++) - { - int xn = x - new_shift[0]; - int yn = y - new_shift[1]; - int zn = z - new_shift[2]; - int index; - float max_den; - - /* skip if cell already belongs to new area */ - if (xn >= min[0] && xn <= max[0] && yn >= min[1] && yn <= max[1] && zn >= min[2] && zn <= max[2]) - continue; - - index = smoke_get_index(x - sds->res_min[0], sds->res[0], y - sds->res_min[1], sds->res[1], z - sds->res_min[2]); - max_den = (fuel) ? MAX2(density[index], fuel[index]) : density[index]; - - /* check high resolution bounds if max density isnt already high enough */ - if (max_den < sds->adapt_threshold && sds->flags & MOD_SMOKE_HIGHRES && sds->wt) { - int i, j, k; - /* high res grid index */ - int xx = (x - sds->res_min[0]) * block_size; - int yy = (y - sds->res_min[1]) * block_size; - int zz = (z - sds->res_min[2]) * block_size; - - for (i = 0; i < block_size; i++) - for (j = 0; j < block_size; j++) - for (k = 0; k < block_size; k++) - { - int big_index = smoke_get_index(xx + i, wt_res[0], yy + j, wt_res[1], zz + k); - float den = (bigfuel) ? MAX2(bigdensity[big_index], bigfuel[big_index]) : bigdensity[big_index]; - if (den > max_den) { - max_den = den; - } - } - } - - /* content bounds (use shifted coordinates) */ - if (max_den >= sds->adapt_threshold) { - if (min[0] > xn) min[0] = xn; - if (min[1] > yn) min[1] = yn; - if (min[2] > zn) min[2] = zn; - if (max[0] < xn) max[0] = xn; - if (max[1] < yn) max[1] = yn; - if (max[2] < zn) max[2] = zn; - } - - /* velocity bounds */ - if (min_vel[0] > vx[index]) min_vel[0] = vx[index]; - if (min_vel[1] > vy[index]) min_vel[1] = vy[index]; - if (min_vel[2] > vz[index]) min_vel[2] = vz[index]; - if (max_vel[0] < vx[index]) max_vel[0] = vx[index]; - if (max_vel[1] < vy[index]) max_vel[1] = vy[index]; - if (max_vel[2] < vz[index]) max_vel[2] = vz[index]; - } - - /* also apply emission maps */ - for (int i = 0; i < numflowobj; i++) { - EmissionMap *em = &emaps[i]; - - for (x = em->min[0]; x < em->max[0]; x++) - for (y = em->min[1]; y < em->max[1]; y++) - for (z = em->min[2]; z < em->max[2]; z++) - { - int index = smoke_get_index(x - em->min[0], em->res[0], y - em->min[1], em->res[1], z - em->min[2]); - float max_den = em->influence[index]; - - /* density bounds */ - if (max_den >= sds->adapt_threshold) { - if (min[0] > x) min[0] = x; - if (min[1] > y) min[1] = y; - if (min[2] > z) min[2] = z; - if (max[0] < x) max[0] = x; - if (max[1] < y) max[1] = y; - if (max[2] < z) max[2] = z; - } - } - } - - /* calculate new bounds based on these values */ - mul_v3_fl(min_vel, 1.0f / sds->dx); - mul_v3_fl(max_vel, 1.0f / sds->dx); - clampBoundsInDomain(sds, min, max, min_vel, max_vel, sds->adapt_margin + 1, dt); - - for (int i = 0; i < 3; i++) { - /* calculate new resolution */ - res[i] = max[i] - min[i]; - total_cells *= res[i]; - - if (new_shift[i]) - shift_changed = 1; - - /* if no content set minimum dimensions */ - if (res[i] <= 0) { - int j; - for (j = 0; j < 3; j++) { - min[j] = 0; - max[j] = 1; - res[j] = 1; - } - res_changed = 1; - total_cells = 1; - break; - } - if (min[i] != sds->res_min[i] || max[i] != sds->res_max[i]) - res_changed = 1; - } - - if (res_changed || shift_changed) { - struct FLUID_3D *fluid_old = sds->fluid; - struct WTURBULENCE *turb_old = sds->wt; - /* allocate new fluid data */ - BKE_smoke_reallocate_fluid(sds, sds->dx, res, 0); - if (sds->flags & MOD_SMOKE_HIGHRES) { - BKE_smoke_reallocate_highres_fluid(sds, sds->dx, res, 0); - } - - /* copy values from old fluid to new */ - if (sds->total_cells > 1 && total_cells > 1) { - /* low res smoke */ - float *o_dens, *o_react, *o_flame, *o_fuel, *o_heat, *o_heatold, *o_vx, *o_vy, *o_vz, *o_r, *o_g, *o_b; - float *n_dens, *n_react, *n_flame, *n_fuel, *n_heat, *n_heatold, *n_vx, *n_vy, *n_vz, *n_r, *n_g, *n_b; - float dummy; - unsigned char *dummy_p; - /* high res smoke */ - int wt_res_old[3]; - float *o_wt_dens, *o_wt_react, *o_wt_flame, *o_wt_fuel, *o_wt_tcu, *o_wt_tcv, *o_wt_tcw, *o_wt_r, *o_wt_g, *o_wt_b; - float *n_wt_dens, *n_wt_react, *n_wt_flame, *n_wt_fuel, *n_wt_tcu, *n_wt_tcv, *n_wt_tcw, *n_wt_r, *n_wt_g, *n_wt_b; - - smoke_export(fluid_old, &dummy, &dummy, &o_dens, &o_react, &o_flame, &o_fuel, &o_heat, &o_heatold, &o_vx, &o_vy, &o_vz, &o_r, &o_g, &o_b, &dummy_p); - smoke_export(sds->fluid, &dummy, &dummy, &n_dens, &n_react, &n_flame, &n_fuel, &n_heat, &n_heatold, &n_vx, &n_vy, &n_vz, &n_r, &n_g, &n_b, &dummy_p); - - if (sds->flags & MOD_SMOKE_HIGHRES) { - smoke_turbulence_export(turb_old, &o_wt_dens, &o_wt_react, &o_wt_flame, &o_wt_fuel, &o_wt_r, &o_wt_g, &o_wt_b, &o_wt_tcu, &o_wt_tcv, &o_wt_tcw); - smoke_turbulence_get_res(turb_old, wt_res_old); - smoke_turbulence_export(sds->wt, &n_wt_dens, &n_wt_react, &n_wt_flame, &n_wt_fuel, &n_wt_r, &n_wt_g, &n_wt_b, &n_wt_tcu, &n_wt_tcv, &n_wt_tcw); - } - - - for (x = sds->res_min[0]; x < sds->res_max[0]; x++) - for (y = sds->res_min[1]; y < sds->res_max[1]; y++) - for (z = sds->res_min[2]; z < sds->res_max[2]; z++) - { - /* old grid index */ - int xo = x - sds->res_min[0]; - int yo = y - sds->res_min[1]; - int zo = z - sds->res_min[2]; - int index_old = smoke_get_index(xo, sds->res[0], yo, sds->res[1], zo); - /* new grid index */ - int xn = x - min[0] - new_shift[0]; - int yn = y - min[1] - new_shift[1]; - int zn = z - min[2] - new_shift[2]; - int index_new = smoke_get_index(xn, res[0], yn, res[1], zn); - - /* skip if outside new domain */ - if (xn < 0 || xn >= res[0] || - yn < 0 || yn >= res[1] || - zn < 0 || zn >= res[2]) - continue; - - /* copy data */ - n_dens[index_new] = o_dens[index_old]; - /* heat */ - if (n_heat && o_heat) { - n_heat[index_new] = o_heat[index_old]; - n_heatold[index_new] = o_heatold[index_old]; - } - /* fuel */ - if (n_fuel && o_fuel) { - n_flame[index_new] = o_flame[index_old]; - n_fuel[index_new] = o_fuel[index_old]; - n_react[index_new] = o_react[index_old]; - } - /* color */ - if (o_r && n_r) { - n_r[index_new] = o_r[index_old]; - n_g[index_new] = o_g[index_old]; - n_b[index_new] = o_b[index_old]; - } - n_vx[index_new] = o_vx[index_old]; - n_vy[index_new] = o_vy[index_old]; - n_vz[index_new] = o_vz[index_old]; - - if (sds->flags & MOD_SMOKE_HIGHRES && turb_old) { - int i, j, k; - /* old grid index */ - int xx_o = xo * block_size; - int yy_o = yo * block_size; - int zz_o = zo * block_size; - /* new grid index */ - int xx_n = xn * block_size; - int yy_n = yn * block_size; - int zz_n = zn * block_size; - - n_wt_tcu[index_new] = o_wt_tcu[index_old]; - n_wt_tcv[index_new] = o_wt_tcv[index_old]; - n_wt_tcw[index_new] = o_wt_tcw[index_old]; - - for (i = 0; i < block_size; i++) - for (j = 0; j < block_size; j++) - for (k = 0; k < block_size; k++) - { - int big_index_old = smoke_get_index(xx_o + i, wt_res_old[0], yy_o + j, wt_res_old[1], zz_o + k); - int big_index_new = smoke_get_index(xx_n + i, sds->res_wt[0], yy_n + j, sds->res_wt[1], zz_n + k); - /* copy data */ - n_wt_dens[big_index_new] = o_wt_dens[big_index_old]; - if (n_wt_flame && o_wt_flame) { - n_wt_flame[big_index_new] = o_wt_flame[big_index_old]; - n_wt_fuel[big_index_new] = o_wt_fuel[big_index_old]; - n_wt_react[big_index_new] = o_wt_react[big_index_old]; - } - if (n_wt_r && o_wt_r) { - n_wt_r[big_index_new] = o_wt_r[big_index_old]; - n_wt_g[big_index_new] = o_wt_g[big_index_old]; - n_wt_b[big_index_new] = o_wt_b[big_index_old]; - } - } - } - } - } - smoke_free(fluid_old); - if (turb_old) - smoke_turbulence_free(turb_old); - - /* set new domain dimensions */ - copy_v3_v3_int(sds->res_min, min); - copy_v3_v3_int(sds->res_max, max); - copy_v3_v3_int(sds->res, res); - sds->total_cells = total_cells; - } + const int block_size = sds->amplify + 1; + int min[3] = {32767, 32767, 32767}, max[3] = {-32767, -32767, -32767}, res[3]; + int total_cells = 1, res_changed = 0, shift_changed = 0; + float min_vel[3], max_vel[3]; + int x, y, z; + float *density = smoke_get_density(sds->fluid); + float *fuel = smoke_get_fuel(sds->fluid); + float *bigdensity = smoke_turbulence_get_density(sds->wt); + float *bigfuel = smoke_turbulence_get_fuel(sds->wt); + float *vx = smoke_get_velocity_x(sds->fluid); + float *vy = smoke_get_velocity_y(sds->fluid); + float *vz = smoke_get_velocity_z(sds->fluid); + int wt_res[3]; + + if (sds->flags & MOD_SMOKE_HIGHRES && sds->wt) { + smoke_turbulence_get_res(sds->wt, wt_res); + } + + INIT_MINMAX(min_vel, max_vel); + + /* Calculate bounds for current domain content */ + for (x = sds->res_min[0]; x < sds->res_max[0]; x++) + for (y = sds->res_min[1]; y < sds->res_max[1]; y++) + for (z = sds->res_min[2]; z < sds->res_max[2]; z++) { + int xn = x - new_shift[0]; + int yn = y - new_shift[1]; + int zn = z - new_shift[2]; + int index; + float max_den; + + /* skip if cell already belongs to new area */ + if (xn >= min[0] && xn <= max[0] && yn >= min[1] && yn <= max[1] && zn >= min[2] && + zn <= max[2]) + continue; + + index = smoke_get_index(x - sds->res_min[0], + sds->res[0], + y - sds->res_min[1], + sds->res[1], + z - sds->res_min[2]); + max_den = (fuel) ? MAX2(density[index], fuel[index]) : density[index]; + + /* check high resolution bounds if max density isnt already high enough */ + if (max_den < sds->adapt_threshold && sds->flags & MOD_SMOKE_HIGHRES && sds->wt) { + int i, j, k; + /* high res grid index */ + int xx = (x - sds->res_min[0]) * block_size; + int yy = (y - sds->res_min[1]) * block_size; + int zz = (z - sds->res_min[2]) * block_size; + + for (i = 0; i < block_size; i++) + for (j = 0; j < block_size; j++) + for (k = 0; k < block_size; k++) { + int big_index = smoke_get_index(xx + i, wt_res[0], yy + j, wt_res[1], zz + k); + float den = (bigfuel) ? MAX2(bigdensity[big_index], bigfuel[big_index]) : + bigdensity[big_index]; + if (den > max_den) { + max_den = den; + } + } + } + + /* content bounds (use shifted coordinates) */ + if (max_den >= sds->adapt_threshold) { + if (min[0] > xn) + min[0] = xn; + if (min[1] > yn) + min[1] = yn; + if (min[2] > zn) + min[2] = zn; + if (max[0] < xn) + max[0] = xn; + if (max[1] < yn) + max[1] = yn; + if (max[2] < zn) + max[2] = zn; + } + + /* velocity bounds */ + if (min_vel[0] > vx[index]) + min_vel[0] = vx[index]; + if (min_vel[1] > vy[index]) + min_vel[1] = vy[index]; + if (min_vel[2] > vz[index]) + min_vel[2] = vz[index]; + if (max_vel[0] < vx[index]) + max_vel[0] = vx[index]; + if (max_vel[1] < vy[index]) + max_vel[1] = vy[index]; + if (max_vel[2] < vz[index]) + max_vel[2] = vz[index]; + } + + /* also apply emission maps */ + for (int i = 0; i < numflowobj; i++) { + EmissionMap *em = &emaps[i]; + + for (x = em->min[0]; x < em->max[0]; x++) + for (y = em->min[1]; y < em->max[1]; y++) + for (z = em->min[2]; z < em->max[2]; z++) { + int index = smoke_get_index( + x - em->min[0], em->res[0], y - em->min[1], em->res[1], z - em->min[2]); + float max_den = em->influence[index]; + + /* density bounds */ + if (max_den >= sds->adapt_threshold) { + if (min[0] > x) + min[0] = x; + if (min[1] > y) + min[1] = y; + if (min[2] > z) + min[2] = z; + if (max[0] < x) + max[0] = x; + if (max[1] < y) + max[1] = y; + if (max[2] < z) + max[2] = z; + } + } + } + + /* calculate new bounds based on these values */ + mul_v3_fl(min_vel, 1.0f / sds->dx); + mul_v3_fl(max_vel, 1.0f / sds->dx); + clampBoundsInDomain(sds, min, max, min_vel, max_vel, sds->adapt_margin + 1, dt); + + for (int i = 0; i < 3; i++) { + /* calculate new resolution */ + res[i] = max[i] - min[i]; + total_cells *= res[i]; + + if (new_shift[i]) + shift_changed = 1; + + /* if no content set minimum dimensions */ + if (res[i] <= 0) { + int j; + for (j = 0; j < 3; j++) { + min[j] = 0; + max[j] = 1; + res[j] = 1; + } + res_changed = 1; + total_cells = 1; + break; + } + if (min[i] != sds->res_min[i] || max[i] != sds->res_max[i]) + res_changed = 1; + } + + if (res_changed || shift_changed) { + struct FLUID_3D *fluid_old = sds->fluid; + struct WTURBULENCE *turb_old = sds->wt; + /* allocate new fluid data */ + BKE_smoke_reallocate_fluid(sds, sds->dx, res, 0); + if (sds->flags & MOD_SMOKE_HIGHRES) { + BKE_smoke_reallocate_highres_fluid(sds, sds->dx, res, 0); + } + + /* copy values from old fluid to new */ + if (sds->total_cells > 1 && total_cells > 1) { + /* low res smoke */ + float *o_dens, *o_react, *o_flame, *o_fuel, *o_heat, *o_heatold, *o_vx, *o_vy, *o_vz, *o_r, + *o_g, *o_b; + float *n_dens, *n_react, *n_flame, *n_fuel, *n_heat, *n_heatold, *n_vx, *n_vy, *n_vz, *n_r, + *n_g, *n_b; + float dummy; + unsigned char *dummy_p; + /* high res smoke */ + int wt_res_old[3]; + float *o_wt_dens, *o_wt_react, *o_wt_flame, *o_wt_fuel, *o_wt_tcu, *o_wt_tcv, *o_wt_tcw, + *o_wt_r, *o_wt_g, *o_wt_b; + float *n_wt_dens, *n_wt_react, *n_wt_flame, *n_wt_fuel, *n_wt_tcu, *n_wt_tcv, *n_wt_tcw, + *n_wt_r, *n_wt_g, *n_wt_b; + + smoke_export(fluid_old, + &dummy, + &dummy, + &o_dens, + &o_react, + &o_flame, + &o_fuel, + &o_heat, + &o_heatold, + &o_vx, + &o_vy, + &o_vz, + &o_r, + &o_g, + &o_b, + &dummy_p); + smoke_export(sds->fluid, + &dummy, + &dummy, + &n_dens, + &n_react, + &n_flame, + &n_fuel, + &n_heat, + &n_heatold, + &n_vx, + &n_vy, + &n_vz, + &n_r, + &n_g, + &n_b, + &dummy_p); + + if (sds->flags & MOD_SMOKE_HIGHRES) { + smoke_turbulence_export(turb_old, + &o_wt_dens, + &o_wt_react, + &o_wt_flame, + &o_wt_fuel, + &o_wt_r, + &o_wt_g, + &o_wt_b, + &o_wt_tcu, + &o_wt_tcv, + &o_wt_tcw); + smoke_turbulence_get_res(turb_old, wt_res_old); + smoke_turbulence_export(sds->wt, + &n_wt_dens, + &n_wt_react, + &n_wt_flame, + &n_wt_fuel, + &n_wt_r, + &n_wt_g, + &n_wt_b, + &n_wt_tcu, + &n_wt_tcv, + &n_wt_tcw); + } + + for (x = sds->res_min[0]; x < sds->res_max[0]; x++) + for (y = sds->res_min[1]; y < sds->res_max[1]; y++) + for (z = sds->res_min[2]; z < sds->res_max[2]; z++) { + /* old grid index */ + int xo = x - sds->res_min[0]; + int yo = y - sds->res_min[1]; + int zo = z - sds->res_min[2]; + int index_old = smoke_get_index(xo, sds->res[0], yo, sds->res[1], zo); + /* new grid index */ + int xn = x - min[0] - new_shift[0]; + int yn = y - min[1] - new_shift[1]; + int zn = z - min[2] - new_shift[2]; + int index_new = smoke_get_index(xn, res[0], yn, res[1], zn); + + /* skip if outside new domain */ + if (xn < 0 || xn >= res[0] || yn < 0 || yn >= res[1] || zn < 0 || zn >= res[2]) + continue; + + /* copy data */ + n_dens[index_new] = o_dens[index_old]; + /* heat */ + if (n_heat && o_heat) { + n_heat[index_new] = o_heat[index_old]; + n_heatold[index_new] = o_heatold[index_old]; + } + /* fuel */ + if (n_fuel && o_fuel) { + n_flame[index_new] = o_flame[index_old]; + n_fuel[index_new] = o_fuel[index_old]; + n_react[index_new] = o_react[index_old]; + } + /* color */ + if (o_r && n_r) { + n_r[index_new] = o_r[index_old]; + n_g[index_new] = o_g[index_old]; + n_b[index_new] = o_b[index_old]; + } + n_vx[index_new] = o_vx[index_old]; + n_vy[index_new] = o_vy[index_old]; + n_vz[index_new] = o_vz[index_old]; + + if (sds->flags & MOD_SMOKE_HIGHRES && turb_old) { + int i, j, k; + /* old grid index */ + int xx_o = xo * block_size; + int yy_o = yo * block_size; + int zz_o = zo * block_size; + /* new grid index */ + int xx_n = xn * block_size; + int yy_n = yn * block_size; + int zz_n = zn * block_size; + + n_wt_tcu[index_new] = o_wt_tcu[index_old]; + n_wt_tcv[index_new] = o_wt_tcv[index_old]; + n_wt_tcw[index_new] = o_wt_tcw[index_old]; + + for (i = 0; i < block_size; i++) + for (j = 0; j < block_size; j++) + for (k = 0; k < block_size; k++) { + int big_index_old = smoke_get_index( + xx_o + i, wt_res_old[0], yy_o + j, wt_res_old[1], zz_o + k); + int big_index_new = smoke_get_index( + xx_n + i, sds->res_wt[0], yy_n + j, sds->res_wt[1], zz_n + k); + /* copy data */ + n_wt_dens[big_index_new] = o_wt_dens[big_index_old]; + if (n_wt_flame && o_wt_flame) { + n_wt_flame[big_index_new] = o_wt_flame[big_index_old]; + n_wt_fuel[big_index_new] = o_wt_fuel[big_index_old]; + n_wt_react[big_index_new] = o_wt_react[big_index_old]; + } + if (n_wt_r && o_wt_r) { + n_wt_r[big_index_new] = o_wt_r[big_index_old]; + n_wt_g[big_index_new] = o_wt_g[big_index_old]; + n_wt_b[big_index_new] = o_wt_b[big_index_old]; + } + } + } + } + } + smoke_free(fluid_old); + if (turb_old) + smoke_turbulence_free(turb_old); + + /* set new domain dimensions */ + copy_v3_v3_int(sds->res_min, min); + copy_v3_v3_int(sds->res_max, max); + copy_v3_v3_int(sds->res, res); + sds->total_cells = total_cells; + } } -BLI_INLINE void apply_outflow_fields(int index, float *density, float *heat, float *fuel, float *react, float *color_r, float *color_g, float *color_b) +BLI_INLINE void apply_outflow_fields(int index, + float *density, + float *heat, + float *fuel, + float *react, + float *color_r, + float *color_g, + float *color_b) { - density[index] = 0.f; - if (heat) { - heat[index] = 0.f; - } - if (fuel) { - fuel[index] = 0.f; - react[index] = 0.f; - } - if (color_r) { - color_r[index] = 0.f; - color_g[index] = 0.f; - color_b[index] = 0.f; - } + density[index] = 0.f; + if (heat) { + heat[index] = 0.f; + } + if (fuel) { + fuel[index] = 0.f; + react[index] = 0.f; + } + if (color_r) { + color_r[index] = 0.f; + color_g[index] = 0.f; + color_b[index] = 0.f; + } } -BLI_INLINE void apply_inflow_fields(SmokeFlowSettings *sfs, float emission_value, int index, float *density, float *heat, float *fuel, float *react, float *color_r, float *color_g, float *color_b) +BLI_INLINE void apply_inflow_fields(SmokeFlowSettings *sfs, + float emission_value, + int index, + float *density, + float *heat, + float *fuel, + float *react, + float *color_r, + float *color_g, + float *color_b) { - int absolute_flow = (sfs->flags & MOD_SMOKE_FLOW_ABSOLUTE); - float dens_old = density[index]; - // float fuel_old = (fuel) ? fuel[index] : 0.0f; /* UNUSED */ - float dens_flow = (sfs->type == MOD_SMOKE_FLOW_TYPE_FIRE) ? 0.0f : emission_value * sfs->density; - float fuel_flow = emission_value * sfs->fuel_amount; - /* add heat */ - if (heat && emission_value > 0.0f) { - heat[index] = ADD_IF_LOWER(heat[index], sfs->temp); - } - /* absolute */ - if (absolute_flow) { - if (sfs->type != MOD_SMOKE_FLOW_TYPE_FIRE) { - if (dens_flow > density[index]) - density[index] = dens_flow; - } - if (sfs->type != MOD_SMOKE_FLOW_TYPE_SMOKE && fuel && fuel_flow) { - if (fuel_flow > fuel[index]) - fuel[index] = fuel_flow; - } - } - /* additive */ - else { - if (sfs->type != MOD_SMOKE_FLOW_TYPE_FIRE) { - density[index] += dens_flow; - CLAMP(density[index], 0.0f, 1.0f); - } - if (sfs->type != MOD_SMOKE_FLOW_TYPE_SMOKE && fuel && sfs->fuel_amount) { - fuel[index] += fuel_flow; - CLAMP(fuel[index], 0.0f, 10.0f); - } - } - - /* set color */ - if (color_r && dens_flow) { - float total_dens = density[index] / (dens_old + dens_flow); - color_r[index] = (color_r[index] + sfs->color[0] * dens_flow) * total_dens; - color_g[index] = (color_g[index] + sfs->color[1] * dens_flow) * total_dens; - color_b[index] = (color_b[index] + sfs->color[2] * dens_flow) * total_dens; - } - - /* set fire reaction coordinate */ - if (fuel && fuel[index] > FLT_EPSILON) { - /* instead of using 1.0 for all new fuel add slight falloff - * to reduce flow blockiness */ - float value = 1.0f - pow2f(1.0f - emission_value); - - if (value > react[index]) { - float f = fuel_flow / fuel[index]; - react[index] = value * f + (1.0f - f) * react[index]; - CLAMP(react[index], 0.0f, value); - } - } + int absolute_flow = (sfs->flags & MOD_SMOKE_FLOW_ABSOLUTE); + float dens_old = density[index]; + // float fuel_old = (fuel) ? fuel[index] : 0.0f; /* UNUSED */ + float dens_flow = (sfs->type == MOD_SMOKE_FLOW_TYPE_FIRE) ? 0.0f : emission_value * sfs->density; + float fuel_flow = emission_value * sfs->fuel_amount; + /* add heat */ + if (heat && emission_value > 0.0f) { + heat[index] = ADD_IF_LOWER(heat[index], sfs->temp); + } + /* absolute */ + if (absolute_flow) { + if (sfs->type != MOD_SMOKE_FLOW_TYPE_FIRE) { + if (dens_flow > density[index]) + density[index] = dens_flow; + } + if (sfs->type != MOD_SMOKE_FLOW_TYPE_SMOKE && fuel && fuel_flow) { + if (fuel_flow > fuel[index]) + fuel[index] = fuel_flow; + } + } + /* additive */ + else { + if (sfs->type != MOD_SMOKE_FLOW_TYPE_FIRE) { + density[index] += dens_flow; + CLAMP(density[index], 0.0f, 1.0f); + } + if (sfs->type != MOD_SMOKE_FLOW_TYPE_SMOKE && fuel && sfs->fuel_amount) { + fuel[index] += fuel_flow; + CLAMP(fuel[index], 0.0f, 10.0f); + } + } + + /* set color */ + if (color_r && dens_flow) { + float total_dens = density[index] / (dens_old + dens_flow); + color_r[index] = (color_r[index] + sfs->color[0] * dens_flow) * total_dens; + color_g[index] = (color_g[index] + sfs->color[1] * dens_flow) * total_dens; + color_b[index] = (color_b[index] + sfs->color[2] * dens_flow) * total_dens; + } + + /* set fire reaction coordinate */ + if (fuel && fuel[index] > FLT_EPSILON) { + /* instead of using 1.0 for all new fuel add slight falloff + * to reduce flow blockiness */ + float value = 1.0f - pow2f(1.0f - emission_value); + + if (value > react[index]) { + float f = fuel_flow / fuel[index]; + react[index] = value * f + (1.0f - f) * react[index]; + CLAMP(react[index], 0.0f, value); + } + } } static void update_flowsfluids( - Depsgraph *depsgraph, Scene *scene, Object *ob, SmokeDomainSettings *sds, float dt) + Depsgraph *depsgraph, Scene *scene, Object *ob, SmokeDomainSettings *sds, float dt) { - Object **flowobjs = NULL; - EmissionMap *emaps = NULL; - unsigned int numflowobj = 0; - unsigned int flowIndex; - int new_shift[3] = {0}; - int active_fields = sds->active_fields; - - /* calculate domain shift for current frame if using adaptive domain */ - if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) { - int total_shift[3]; - float frame_shift_f[3]; - float ob_loc[3] = {0}; - - mul_m4_v3(ob->obmat, ob_loc); - - sub_v3_v3v3(frame_shift_f, ob_loc, sds->prev_loc); - copy_v3_v3(sds->prev_loc, ob_loc); - /* convert global space shift to local "cell" space */ - mul_mat3_m4_v3(sds->imat, frame_shift_f); - frame_shift_f[0] = frame_shift_f[0] / sds->cell_size[0]; - frame_shift_f[1] = frame_shift_f[1] / sds->cell_size[1]; - frame_shift_f[2] = frame_shift_f[2] / sds->cell_size[2]; - /* add to total shift */ - add_v3_v3(sds->shift_f, frame_shift_f); - /* convert to integer */ - total_shift[0] = (int)(floorf(sds->shift_f[0])); - total_shift[1] = (int)(floorf(sds->shift_f[1])); - total_shift[2] = (int)(floorf(sds->shift_f[2])); - sub_v3_v3v3_int(new_shift, total_shift, sds->shift); - copy_v3_v3_int(sds->shift, total_shift); - - /* calculate new domain boundary points so that smoke doesn't slide on sub-cell movement */ - sds->p0[0] = sds->dp0[0] - sds->cell_size[0] * (sds->shift_f[0] - total_shift[0] - 0.5f); - sds->p0[1] = sds->dp0[1] - sds->cell_size[1] * (sds->shift_f[1] - total_shift[1] - 0.5f); - sds->p0[2] = sds->dp0[2] - sds->cell_size[2] * (sds->shift_f[2] - total_shift[2] - 0.5f); - sds->p1[0] = sds->p0[0] + sds->cell_size[0] * sds->base_res[0]; - sds->p1[1] = sds->p0[1] + sds->cell_size[1] * sds->base_res[1]; - sds->p1[2] = sds->p0[2] + sds->cell_size[2] * sds->base_res[2]; - } - - flowobjs = BKE_collision_objects_create(depsgraph, ob, sds->fluid_group, &numflowobj, eModifierType_Smoke); - - /* init emission maps for each flow */ - emaps = MEM_callocN(sizeof(struct EmissionMap) * numflowobj, "smoke_flow_maps"); - - /* Prepare flow emission maps */ - for (flowIndex = 0; flowIndex < numflowobj; flowIndex++) - { - Object *collob = flowobjs[flowIndex]; - SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(collob, eModifierType_Smoke); - - // check for initialized smoke object - if ((smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow) - { - // we got nice flow object - SmokeFlowSettings *sfs = smd2->flow; - int subframes = sfs->subframes; - EmissionMap *em = &emaps[flowIndex]; - - /* just sample flow directly to emission map if no subframes */ - if (!subframes) { - if (sfs->source == MOD_SMOKE_FLOW_SOURCE_PARTICLES) { - emit_from_particles(collob, sds, sfs, em, depsgraph, scene, dt); - } - else { - emit_from_mesh(collob, sds, sfs, em, dt); - } - } - /* sample subframes */ - else { -#if 0 - int scene_frame = (int)DEG_get_ctime(depsgraph); -#endif - // float scene_subframe = scene->r.subframe; // UNUSED - int subframe; - for (subframe = 0; subframe <= subframes; subframe++) { - EmissionMap em_temp = {NULL}; - float sample_size = 1.0f / (float)(subframes+1); -#if 0 - float prev_frame_pos = sample_size * (float)(subframe+1); -#endif - float sdt = dt * sample_size; - int hires_multiplier = 1; - - if ((sds->flags & MOD_SMOKE_HIGHRES) && (sds->highres_sampling == SM_HRES_FULLSAMPLE)) { - hires_multiplier = sds->amplify + 1; - } - - /* TODO: setting the scene frame no longer works with the new depsgraph. */ -#if 0 - /* set scene frame to match previous frame + subframe - * or use current frame for last sample */ - if (subframe < subframes) { - scene->r.cfra = scene_frame - 1; - scene->r.subframe = prev_frame_pos; - } - else { - scene->r.cfra = scene_frame; - scene->r.subframe = 0.0f; - } -#endif - - if (sfs->source == MOD_SMOKE_FLOW_SOURCE_PARTICLES) { - /* emit_from_particles() updates timestep internally */ - emit_from_particles(collob, sds, sfs, &em_temp, depsgraph, scene, sdt); - if (!(sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE)) { - hires_multiplier = 1; - } - } - else { /* MOD_SMOKE_FLOW_SOURCE_MESH */ - /* update flow object frame */ - BLI_mutex_lock(&object_update_lock); - BKE_object_modifier_update_subframe(depsgraph, scene, collob, true, 5, DEG_get_ctime(depsgraph), eModifierType_Smoke); - BLI_mutex_unlock(&object_update_lock); - - /* apply flow */ - emit_from_mesh(collob, sds, sfs, &em_temp, sdt); - } - - /* combine emission maps */ - em_combineMaps(em, &em_temp, hires_multiplier, !(sfs->flags & MOD_SMOKE_FLOW_ABSOLUTE), sample_size); - em_freeData(&em_temp); - } - } - - /* update required data fields */ - if (em->total_cells && sfs->type != MOD_SMOKE_FLOW_TYPE_OUTFLOW) { - /* activate heat field if flow produces any heat */ - if (sfs->temp) { - active_fields |= SM_ACTIVE_HEAT; - } - /* activate fuel field if flow adds any fuel */ - if (sfs->type != MOD_SMOKE_FLOW_TYPE_SMOKE && sfs->fuel_amount) { - active_fields |= SM_ACTIVE_FIRE; - } - /* activate color field if flows add smoke with varying colors */ - if (sfs->type != MOD_SMOKE_FLOW_TYPE_FIRE && sfs->density) { - if (!(active_fields & SM_ACTIVE_COLOR_SET)) { - copy_v3_v3(sds->active_color, sfs->color); - active_fields |= SM_ACTIVE_COLOR_SET; - } - else if (!equals_v3v3(sds->active_color, sfs->color)) { - copy_v3_v3(sds->active_color, sfs->color); - active_fields |= SM_ACTIVE_COLORS; - } - } - } - } - } - - /* monitor active fields based on domain settings */ - /* if domain has fire, activate new fields if required */ - if (active_fields & SM_ACTIVE_FIRE) { - /* heat is always needed for fire */ - active_fields |= SM_ACTIVE_HEAT; - /* also activate colors if domain smoke color differs from active color */ - if (!(active_fields & SM_ACTIVE_COLOR_SET)) { - copy_v3_v3(sds->active_color, sds->flame_smoke_color); - active_fields |= SM_ACTIVE_COLOR_SET; - } - else if (!equals_v3v3(sds->active_color, sds->flame_smoke_color)) { - copy_v3_v3(sds->active_color, sds->flame_smoke_color); - active_fields |= SM_ACTIVE_COLORS; - } - } - - /* Adjust domain size if needed */ - if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) { - adjustDomainResolution(sds, new_shift, emaps, numflowobj, dt); - } - - /* Initialize new data fields if any */ - if (active_fields & SM_ACTIVE_HEAT) { - smoke_ensure_heat(sds->fluid); - } - if (active_fields & SM_ACTIVE_FIRE) { - smoke_ensure_fire(sds->fluid, sds->wt); - } - if (active_fields & SM_ACTIVE_COLORS) { - /* initialize all smoke with "active_color" */ - smoke_ensure_colors(sds->fluid, sds->wt, sds->active_color[0], sds->active_color[1], sds->active_color[2]); - } - sds->active_fields = active_fields; - - /* Apply emission data */ - if (sds->fluid) { - for (flowIndex = 0; flowIndex < numflowobj; flowIndex++) - { - Object *collob = flowobjs[flowIndex]; - SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(collob, eModifierType_Smoke); - - // check for initialized smoke object - if ((smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow) - { - // we got nice flow object - SmokeFlowSettings *sfs = smd2->flow; - EmissionMap *em = &emaps[flowIndex]; - - float *density = smoke_get_density(sds->fluid); - float *color_r = smoke_get_color_r(sds->fluid); - float *color_g = smoke_get_color_g(sds->fluid); - float *color_b = smoke_get_color_b(sds->fluid); - float *fuel = smoke_get_fuel(sds->fluid); - float *react = smoke_get_react(sds->fluid); - float *bigdensity = smoke_turbulence_get_density(sds->wt); - float *bigfuel = smoke_turbulence_get_fuel(sds->wt); - float *bigreact = smoke_turbulence_get_react(sds->wt); - float *bigcolor_r = smoke_turbulence_get_color_r(sds->wt); - float *bigcolor_g = smoke_turbulence_get_color_g(sds->wt); - float *bigcolor_b = smoke_turbulence_get_color_b(sds->wt); - float *heat = smoke_get_heat(sds->fluid); - float *velocity_x = smoke_get_velocity_x(sds->fluid); - float *velocity_y = smoke_get_velocity_y(sds->fluid); - float *velocity_z = smoke_get_velocity_z(sds->fluid); - //unsigned char *obstacle = smoke_get_obstacle(sds->fluid); - // DG TODO UNUSED unsigned char *obstacleAnim = smoke_get_obstacle_anim(sds->fluid); - int bigres[3]; - float *velocity_map = em->velocity; - float *emission_map = em->influence; - float *emission_map_high = em->influence_high; - - int ii, jj, kk, gx, gy, gz, ex, ey, ez, dx, dy, dz, block_size; - size_t e_index, d_index, index_big; - - // loop through every emission map cell - for (gx = em->min[0]; gx < em->max[0]; gx++) - for (gy = em->min[1]; gy < em->max[1]; gy++) - for (gz = em->min[2]; gz < em->max[2]; gz++) - { - /* get emission map index */ - ex = gx - em->min[0]; - ey = gy - em->min[1]; - ez = gz - em->min[2]; - e_index = smoke_get_index(ex, em->res[0], ey, em->res[1], ez); - - /* get domain index */ - dx = gx - sds->res_min[0]; - dy = gy - sds->res_min[1]; - dz = gz - sds->res_min[2]; - d_index = smoke_get_index(dx, sds->res[0], dy, sds->res[1], dz); - /* make sure emission cell is inside the new domain boundary */ - if (dx < 0 || dy < 0 || dz < 0 || dx >= sds->res[0] || dy >= sds->res[1] || dz >= sds->res[2]) continue; - - if (sfs->type == MOD_SMOKE_FLOW_TYPE_OUTFLOW) { // outflow - apply_outflow_fields(d_index, density, heat, fuel, react, color_r, color_g, color_b); - } - else { // inflow - apply_inflow_fields(sfs, emission_map[e_index], d_index, density, heat, fuel, react, color_r, color_g, color_b); - - /* initial velocity */ - if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY) { - velocity_x[d_index] = ADD_IF_LOWER(velocity_x[d_index], velocity_map[e_index * 3]); - velocity_y[d_index] = ADD_IF_LOWER(velocity_y[d_index], velocity_map[e_index * 3 + 1]); - velocity_z[d_index] = ADD_IF_LOWER(velocity_z[d_index], velocity_map[e_index * 3 + 2]); - } - } - - /* loop through high res blocks if high res enabled */ - if (bigdensity) { - // neighbor cell emission densities (for high resolution smoke smooth interpolation) - float c000, c001, c010, c011, c100, c101, c110, c111; - - smoke_turbulence_get_res(sds->wt, bigres); - block_size = sds->amplify + 1; // high res block size - - c000 = (ex > 0 && ey > 0 && ez > 0) ? emission_map[smoke_get_index(ex - 1, em->res[0], ey - 1, em->res[1], ez - 1)] : 0; - c001 = (ex > 0 && ey > 0) ? emission_map[smoke_get_index(ex - 1, em->res[0], ey - 1, em->res[1], ez)] : 0; - c010 = (ex > 0 && ez > 0) ? emission_map[smoke_get_index(ex - 1, em->res[0], ey, em->res[1], ez - 1)] : 0; - c011 = (ex > 0) ? emission_map[smoke_get_index(ex - 1, em->res[0], ey, em->res[1], ez)] : 0; - - c100 = (ey > 0 && ez > 0) ? emission_map[smoke_get_index(ex, em->res[0], ey - 1, em->res[1], ez - 1)] : 0; - c101 = (ey > 0) ? emission_map[smoke_get_index(ex, em->res[0], ey - 1, em->res[1], ez)] : 0; - c110 = (ez > 0) ? emission_map[smoke_get_index(ex, em->res[0], ey, em->res[1], ez - 1)] : 0; - c111 = emission_map[smoke_get_index(ex, em->res[0], ey, em->res[1], ez)]; // this cell - - for (ii = 0; ii < block_size; ii++) - for (jj = 0; jj < block_size; jj++) - for (kk = 0; kk < block_size; kk++) - { - - float fx, fy, fz, interpolated_value; - int shift_x = 0, shift_y = 0, shift_z = 0; - - - /* Use full sample emission map if enabled and available */ - if ((sds->highres_sampling == SM_HRES_FULLSAMPLE) && emission_map_high) { - interpolated_value = emission_map_high[smoke_get_index(ex * block_size + ii, em->res[0] * block_size, ey * block_size + jj, em->res[1] * block_size, ez * block_size + kk)]; // this cell - } - else if (sds->highres_sampling == SM_HRES_NEAREST) { - /* without interpolation use same low resolution - * block value for all hi-res blocks */ - interpolated_value = c111; - } - /* Fall back to interpolated */ - else - { - /* get relative block position - * for interpolation smoothing */ - fx = (float)ii / block_size + 0.5f / block_size; - fy = (float)jj / block_size + 0.5f / block_size; - fz = (float)kk / block_size + 0.5f / block_size; - - /* calculate trilinear interpolation */ - interpolated_value = c000 * (1 - fx) * (1 - fy) * (1 - fz) + - c100 * fx * (1 - fy) * (1 - fz) + - c010 * (1 - fx) * fy * (1 - fz) + - c001 * (1 - fx) * (1 - fy) * fz + - c101 * fx * (1 - fy) * fz + - c011 * (1 - fx) * fy * fz + - c110 * fx * fy * (1 - fz) + - c111 * fx * fy * fz; - - - /* add some contrast / sharpness - * depending on hi-res block size */ - interpolated_value = (interpolated_value - 0.4f) * (block_size / 2) + 0.4f; - CLAMP(interpolated_value, 0.0f, 1.0f); - - /* shift smoke block index - * (because pixel center is actually - * in halfway of the low res block) */ - shift_x = (dx < 1) ? 0 : block_size / 2; - shift_y = (dy < 1) ? 0 : block_size / 2; - shift_z = (dz < 1) ? 0 : block_size / 2; - } - - /* get shifted index for current high resolution block */ - index_big = smoke_get_index(block_size * dx + ii - shift_x, bigres[0], block_size * dy + jj - shift_y, bigres[1], block_size * dz + kk - shift_z); - - if (sfs->type == MOD_SMOKE_FLOW_TYPE_OUTFLOW) { // outflow - if (interpolated_value) { - apply_outflow_fields(index_big, bigdensity, NULL, bigfuel, bigreact, bigcolor_r, bigcolor_g, bigcolor_b); - } - } - else { // inflow - apply_inflow_fields(sfs, interpolated_value, index_big, bigdensity, NULL, bigfuel, bigreact, bigcolor_r, bigcolor_g, bigcolor_b); - } - } // hires loop - } // bigdensity - } // low res loop - - // free emission maps - em_freeData(em); - - } // end emission - } - } - - BKE_collision_objects_free(flowobjs); - if (emaps) - MEM_freeN(emaps); + Object **flowobjs = NULL; + EmissionMap *emaps = NULL; + unsigned int numflowobj = 0; + unsigned int flowIndex; + int new_shift[3] = {0}; + int active_fields = sds->active_fields; + + /* calculate domain shift for current frame if using adaptive domain */ + if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) { + int total_shift[3]; + float frame_shift_f[3]; + float ob_loc[3] = {0}; + + mul_m4_v3(ob->obmat, ob_loc); + + sub_v3_v3v3(frame_shift_f, ob_loc, sds->prev_loc); + copy_v3_v3(sds->prev_loc, ob_loc); + /* convert global space shift to local "cell" space */ + mul_mat3_m4_v3(sds->imat, frame_shift_f); + frame_shift_f[0] = frame_shift_f[0] / sds->cell_size[0]; + frame_shift_f[1] = frame_shift_f[1] / sds->cell_size[1]; + frame_shift_f[2] = frame_shift_f[2] / sds->cell_size[2]; + /* add to total shift */ + add_v3_v3(sds->shift_f, frame_shift_f); + /* convert to integer */ + total_shift[0] = (int)(floorf(sds->shift_f[0])); + total_shift[1] = (int)(floorf(sds->shift_f[1])); + total_shift[2] = (int)(floorf(sds->shift_f[2])); + sub_v3_v3v3_int(new_shift, total_shift, sds->shift); + copy_v3_v3_int(sds->shift, total_shift); + + /* calculate new domain boundary points so that smoke doesn't slide on sub-cell movement */ + sds->p0[0] = sds->dp0[0] - sds->cell_size[0] * (sds->shift_f[0] - total_shift[0] - 0.5f); + sds->p0[1] = sds->dp0[1] - sds->cell_size[1] * (sds->shift_f[1] - total_shift[1] - 0.5f); + sds->p0[2] = sds->dp0[2] - sds->cell_size[2] * (sds->shift_f[2] - total_shift[2] - 0.5f); + sds->p1[0] = sds->p0[0] + sds->cell_size[0] * sds->base_res[0]; + sds->p1[1] = sds->p0[1] + sds->cell_size[1] * sds->base_res[1]; + sds->p1[2] = sds->p0[2] + sds->cell_size[2] * sds->base_res[2]; + } + + flowobjs = BKE_collision_objects_create( + depsgraph, ob, sds->fluid_group, &numflowobj, eModifierType_Smoke); + + /* init emission maps for each flow */ + emaps = MEM_callocN(sizeof(struct EmissionMap) * numflowobj, "smoke_flow_maps"); + + /* Prepare flow emission maps */ + for (flowIndex = 0; flowIndex < numflowobj; flowIndex++) { + Object *collob = flowobjs[flowIndex]; + SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(collob, + eModifierType_Smoke); + + // check for initialized smoke object + if ((smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow) { + // we got nice flow object + SmokeFlowSettings *sfs = smd2->flow; + int subframes = sfs->subframes; + EmissionMap *em = &emaps[flowIndex]; + + /* just sample flow directly to emission map if no subframes */ + if (!subframes) { + if (sfs->source == MOD_SMOKE_FLOW_SOURCE_PARTICLES) { + emit_from_particles(collob, sds, sfs, em, depsgraph, scene, dt); + } + else { + emit_from_mesh(collob, sds, sfs, em, dt); + } + } + /* sample subframes */ + else { +# if 0 + int scene_frame = (int)DEG_get_ctime(depsgraph); +# endif + // float scene_subframe = scene->r.subframe; // UNUSED + int subframe; + for (subframe = 0; subframe <= subframes; subframe++) { + EmissionMap em_temp = {NULL}; + float sample_size = 1.0f / (float)(subframes + 1); +# if 0 + float prev_frame_pos = sample_size * (float)(subframe+1); +# endif + float sdt = dt * sample_size; + int hires_multiplier = 1; + + if ((sds->flags & MOD_SMOKE_HIGHRES) && (sds->highres_sampling == SM_HRES_FULLSAMPLE)) { + hires_multiplier = sds->amplify + 1; + } + + /* TODO: setting the scene frame no longer works with the new depsgraph. */ +# if 0 + /* set scene frame to match previous frame + subframe + * or use current frame for last sample */ + if (subframe < subframes) { + scene->r.cfra = scene_frame - 1; + scene->r.subframe = prev_frame_pos; + } + else { + scene->r.cfra = scene_frame; + scene->r.subframe = 0.0f; + } +# endif + + if (sfs->source == MOD_SMOKE_FLOW_SOURCE_PARTICLES) { + /* emit_from_particles() updates timestep internally */ + emit_from_particles(collob, sds, sfs, &em_temp, depsgraph, scene, sdt); + if (!(sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE)) { + hires_multiplier = 1; + } + } + else { /* MOD_SMOKE_FLOW_SOURCE_MESH */ + /* update flow object frame */ + BLI_mutex_lock(&object_update_lock); + BKE_object_modifier_update_subframe( + depsgraph, scene, collob, true, 5, DEG_get_ctime(depsgraph), eModifierType_Smoke); + BLI_mutex_unlock(&object_update_lock); + + /* apply flow */ + emit_from_mesh(collob, sds, sfs, &em_temp, sdt); + } + + /* combine emission maps */ + em_combineMaps(em, + &em_temp, + hires_multiplier, + !(sfs->flags & MOD_SMOKE_FLOW_ABSOLUTE), + sample_size); + em_freeData(&em_temp); + } + } + + /* update required data fields */ + if (em->total_cells && sfs->type != MOD_SMOKE_FLOW_TYPE_OUTFLOW) { + /* activate heat field if flow produces any heat */ + if (sfs->temp) { + active_fields |= SM_ACTIVE_HEAT; + } + /* activate fuel field if flow adds any fuel */ + if (sfs->type != MOD_SMOKE_FLOW_TYPE_SMOKE && sfs->fuel_amount) { + active_fields |= SM_ACTIVE_FIRE; + } + /* activate color field if flows add smoke with varying colors */ + if (sfs->type != MOD_SMOKE_FLOW_TYPE_FIRE && sfs->density) { + if (!(active_fields & SM_ACTIVE_COLOR_SET)) { + copy_v3_v3(sds->active_color, sfs->color); + active_fields |= SM_ACTIVE_COLOR_SET; + } + else if (!equals_v3v3(sds->active_color, sfs->color)) { + copy_v3_v3(sds->active_color, sfs->color); + active_fields |= SM_ACTIVE_COLORS; + } + } + } + } + } + + /* monitor active fields based on domain settings */ + /* if domain has fire, activate new fields if required */ + if (active_fields & SM_ACTIVE_FIRE) { + /* heat is always needed for fire */ + active_fields |= SM_ACTIVE_HEAT; + /* also activate colors if domain smoke color differs from active color */ + if (!(active_fields & SM_ACTIVE_COLOR_SET)) { + copy_v3_v3(sds->active_color, sds->flame_smoke_color); + active_fields |= SM_ACTIVE_COLOR_SET; + } + else if (!equals_v3v3(sds->active_color, sds->flame_smoke_color)) { + copy_v3_v3(sds->active_color, sds->flame_smoke_color); + active_fields |= SM_ACTIVE_COLORS; + } + } + + /* Adjust domain size if needed */ + if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) { + adjustDomainResolution(sds, new_shift, emaps, numflowobj, dt); + } + + /* Initialize new data fields if any */ + if (active_fields & SM_ACTIVE_HEAT) { + smoke_ensure_heat(sds->fluid); + } + if (active_fields & SM_ACTIVE_FIRE) { + smoke_ensure_fire(sds->fluid, sds->wt); + } + if (active_fields & SM_ACTIVE_COLORS) { + /* initialize all smoke with "active_color" */ + smoke_ensure_colors( + sds->fluid, sds->wt, sds->active_color[0], sds->active_color[1], sds->active_color[2]); + } + sds->active_fields = active_fields; + + /* Apply emission data */ + if (sds->fluid) { + for (flowIndex = 0; flowIndex < numflowobj; flowIndex++) { + Object *collob = flowobjs[flowIndex]; + SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(collob, + eModifierType_Smoke); + + // check for initialized smoke object + if ((smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow) { + // we got nice flow object + SmokeFlowSettings *sfs = smd2->flow; + EmissionMap *em = &emaps[flowIndex]; + + float *density = smoke_get_density(sds->fluid); + float *color_r = smoke_get_color_r(sds->fluid); + float *color_g = smoke_get_color_g(sds->fluid); + float *color_b = smoke_get_color_b(sds->fluid); + float *fuel = smoke_get_fuel(sds->fluid); + float *react = smoke_get_react(sds->fluid); + float *bigdensity = smoke_turbulence_get_density(sds->wt); + float *bigfuel = smoke_turbulence_get_fuel(sds->wt); + float *bigreact = smoke_turbulence_get_react(sds->wt); + float *bigcolor_r = smoke_turbulence_get_color_r(sds->wt); + float *bigcolor_g = smoke_turbulence_get_color_g(sds->wt); + float *bigcolor_b = smoke_turbulence_get_color_b(sds->wt); + float *heat = smoke_get_heat(sds->fluid); + float *velocity_x = smoke_get_velocity_x(sds->fluid); + float *velocity_y = smoke_get_velocity_y(sds->fluid); + float *velocity_z = smoke_get_velocity_z(sds->fluid); + //unsigned char *obstacle = smoke_get_obstacle(sds->fluid); + // DG TODO UNUSED unsigned char *obstacleAnim = smoke_get_obstacle_anim(sds->fluid); + int bigres[3]; + float *velocity_map = em->velocity; + float *emission_map = em->influence; + float *emission_map_high = em->influence_high; + + int ii, jj, kk, gx, gy, gz, ex, ey, ez, dx, dy, dz, block_size; + size_t e_index, d_index, index_big; + + // loop through every emission map cell + for (gx = em->min[0]; gx < em->max[0]; gx++) + for (gy = em->min[1]; gy < em->max[1]; gy++) + for (gz = em->min[2]; gz < em->max[2]; gz++) { + /* get emission map index */ + ex = gx - em->min[0]; + ey = gy - em->min[1]; + ez = gz - em->min[2]; + e_index = smoke_get_index(ex, em->res[0], ey, em->res[1], ez); + + /* get domain index */ + dx = gx - sds->res_min[0]; + dy = gy - sds->res_min[1]; + dz = gz - sds->res_min[2]; + d_index = smoke_get_index(dx, sds->res[0], dy, sds->res[1], dz); + /* make sure emission cell is inside the new domain boundary */ + if (dx < 0 || dy < 0 || dz < 0 || dx >= sds->res[0] || dy >= sds->res[1] || + dz >= sds->res[2]) + continue; + + if (sfs->type == MOD_SMOKE_FLOW_TYPE_OUTFLOW) { // outflow + apply_outflow_fields( + d_index, density, heat, fuel, react, color_r, color_g, color_b); + } + else { // inflow + apply_inflow_fields(sfs, + emission_map[e_index], + d_index, + density, + heat, + fuel, + react, + color_r, + color_g, + color_b); + + /* initial velocity */ + if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY) { + velocity_x[d_index] = ADD_IF_LOWER(velocity_x[d_index], + velocity_map[e_index * 3]); + velocity_y[d_index] = ADD_IF_LOWER(velocity_y[d_index], + velocity_map[e_index * 3 + 1]); + velocity_z[d_index] = ADD_IF_LOWER(velocity_z[d_index], + velocity_map[e_index * 3 + 2]); + } + } + + /* loop through high res blocks if high res enabled */ + if (bigdensity) { + // neighbor cell emission densities (for high resolution smoke smooth interpolation) + float c000, c001, c010, c011, c100, c101, c110, c111; + + smoke_turbulence_get_res(sds->wt, bigres); + block_size = sds->amplify + 1; // high res block size + + c000 = (ex > 0 && ey > 0 && ez > 0) ? + emission_map[smoke_get_index( + ex - 1, em->res[0], ey - 1, em->res[1], ez - 1)] : + 0; + c001 = + (ex > 0 && ey > 0) ? + emission_map[smoke_get_index(ex - 1, em->res[0], ey - 1, em->res[1], ez)] : + 0; + c010 = + (ex > 0 && ez > 0) ? + emission_map[smoke_get_index(ex - 1, em->res[0], ey, em->res[1], ez - 1)] : + 0; + c011 = (ex > 0) ? + emission_map[smoke_get_index(ex - 1, em->res[0], ey, em->res[1], ez)] : + 0; + + c100 = + (ey > 0 && ez > 0) ? + emission_map[smoke_get_index(ex, em->res[0], ey - 1, em->res[1], ez - 1)] : + 0; + c101 = (ey > 0) ? + emission_map[smoke_get_index(ex, em->res[0], ey - 1, em->res[1], ez)] : + 0; + c110 = (ez > 0) ? + emission_map[smoke_get_index(ex, em->res[0], ey, em->res[1], ez - 1)] : + 0; + c111 = emission_map[smoke_get_index( + ex, em->res[0], ey, em->res[1], ez)]; // this cell + + for (ii = 0; ii < block_size; ii++) + for (jj = 0; jj < block_size; jj++) + for (kk = 0; kk < block_size; kk++) { + + float fx, fy, fz, interpolated_value; + int shift_x = 0, shift_y = 0, shift_z = 0; + + /* Use full sample emission map if enabled and available */ + if ((sds->highres_sampling == SM_HRES_FULLSAMPLE) && emission_map_high) { + interpolated_value = + emission_map_high[smoke_get_index(ex * block_size + ii, + em->res[0] * block_size, + ey * block_size + jj, + em->res[1] * block_size, + ez * block_size + kk)]; // this cell + } + else if (sds->highres_sampling == SM_HRES_NEAREST) { + /* without interpolation use same low resolution + * block value for all hi-res blocks */ + interpolated_value = c111; + } + /* Fall back to interpolated */ + else { + /* get relative block position + * for interpolation smoothing */ + fx = (float)ii / block_size + 0.5f / block_size; + fy = (float)jj / block_size + 0.5f / block_size; + fz = (float)kk / block_size + 0.5f / block_size; + + /* calculate trilinear interpolation */ + interpolated_value = c000 * (1 - fx) * (1 - fy) * (1 - fz) + + c100 * fx * (1 - fy) * (1 - fz) + + c010 * (1 - fx) * fy * (1 - fz) + + c001 * (1 - fx) * (1 - fy) * fz + + c101 * fx * (1 - fy) * fz + + c011 * (1 - fx) * fy * fz + + c110 * fx * fy * (1 - fz) + c111 * fx * fy * fz; + + /* add some contrast / sharpness + * depending on hi-res block size */ + interpolated_value = (interpolated_value - 0.4f) * (block_size / 2) + 0.4f; + CLAMP(interpolated_value, 0.0f, 1.0f); + + /* shift smoke block index + * (because pixel center is actually + * in halfway of the low res block) */ + shift_x = (dx < 1) ? 0 : block_size / 2; + shift_y = (dy < 1) ? 0 : block_size / 2; + shift_z = (dz < 1) ? 0 : block_size / 2; + } + + /* get shifted index for current high resolution block */ + index_big = smoke_get_index(block_size * dx + ii - shift_x, + bigres[0], + block_size * dy + jj - shift_y, + bigres[1], + block_size * dz + kk - shift_z); + + if (sfs->type == MOD_SMOKE_FLOW_TYPE_OUTFLOW) { // outflow + if (interpolated_value) { + apply_outflow_fields(index_big, + bigdensity, + NULL, + bigfuel, + bigreact, + bigcolor_r, + bigcolor_g, + bigcolor_b); + } + } + else { // inflow + apply_inflow_fields(sfs, + interpolated_value, + index_big, + bigdensity, + NULL, + bigfuel, + bigreact, + bigcolor_r, + bigcolor_g, + bigcolor_b); + } + } // hires loop + } // bigdensity + } // low res loop + + // free emission maps + em_freeData(em); + + } // end emission + } + } + + BKE_collision_objects_free(flowobjs); + if (emaps) + MEM_freeN(emaps); } typedef struct UpdateEffectorsData { - Scene *scene; - SmokeDomainSettings *sds; - ListBase *effectors; - - float *density; - float *fuel; - float *force_x; - float *force_y; - float *force_z; - float *velocity_x; - float *velocity_y; - float *velocity_z; - unsigned char *obstacle; + Scene *scene; + SmokeDomainSettings *sds; + ListBase *effectors; + + float *density; + float *fuel; + float *force_x; + float *force_y; + float *force_z; + float *velocity_x; + float *velocity_y; + float *velocity_z; + unsigned char *obstacle; } UpdateEffectorsData; -static void update_effectors_task_cb( - void *__restrict userdata, - const int x, - const ParallelRangeTLS *__restrict UNUSED(tls)) +static void update_effectors_task_cb(void *__restrict userdata, + const int x, + const ParallelRangeTLS *__restrict UNUSED(tls)) { - UpdateEffectorsData *data = userdata; - SmokeDomainSettings *sds = data->sds; - - for (int y = 0; y < sds->res[1]; y++) { - for (int z = 0; z < sds->res[2]; z++) - { - EffectedPoint epoint; - float mag; - float voxelCenter[3] = {0, 0, 0}, vel[3] = {0, 0, 0}, retvel[3] = {0, 0, 0}; - const unsigned int index = smoke_get_index(x, sds->res[0], y, sds->res[1], z); - - if (((data->fuel ? MAX2(data->density[index], data->fuel[index]) : data->density[index]) < FLT_EPSILON) || - data->obstacle[index]) - { - continue; - } - - vel[0] = data->velocity_x[index]; - vel[1] = data->velocity_y[index]; - vel[2] = data->velocity_z[index]; - - /* convert vel to global space */ - mag = len_v3(vel); - mul_mat3_m4_v3(sds->obmat, vel); - normalize_v3(vel); - mul_v3_fl(vel, mag); - - voxelCenter[0] = sds->p0[0] + sds->cell_size[0] * ((float)(x + sds->res_min[0]) + 0.5f); - voxelCenter[1] = sds->p0[1] + sds->cell_size[1] * ((float)(y + sds->res_min[1]) + 0.5f); - voxelCenter[2] = sds->p0[2] + sds->cell_size[2] * ((float)(z + sds->res_min[2]) + 0.5f); - mul_m4_v3(sds->obmat, voxelCenter); - - pd_point_from_loc(data->scene, voxelCenter, vel, index, &epoint); - BKE_effectors_apply(data->effectors, NULL, sds->effector_weights, &epoint, retvel, NULL); - - /* convert retvel to local space */ - mag = len_v3(retvel); - mul_mat3_m4_v3(sds->imat, retvel); - normalize_v3(retvel); - mul_v3_fl(retvel, mag); - - // TODO dg - do in force! - data->force_x[index] = min_ff(max_ff(-1.0f, retvel[0] * 0.2f), 1.0f); - data->force_y[index] = min_ff(max_ff(-1.0f, retvel[1] * 0.2f), 1.0f); - data->force_z[index] = min_ff(max_ff(-1.0f, retvel[2] * 0.2f), 1.0f); - } - } + UpdateEffectorsData *data = userdata; + SmokeDomainSettings *sds = data->sds; + + for (int y = 0; y < sds->res[1]; y++) { + for (int z = 0; z < sds->res[2]; z++) { + EffectedPoint epoint; + float mag; + float voxelCenter[3] = {0, 0, 0}, vel[3] = {0, 0, 0}, retvel[3] = {0, 0, 0}; + const unsigned int index = smoke_get_index(x, sds->res[0], y, sds->res[1], z); + + if (((data->fuel ? MAX2(data->density[index], data->fuel[index]) : data->density[index]) < + FLT_EPSILON) || + data->obstacle[index]) { + continue; + } + + vel[0] = data->velocity_x[index]; + vel[1] = data->velocity_y[index]; + vel[2] = data->velocity_z[index]; + + /* convert vel to global space */ + mag = len_v3(vel); + mul_mat3_m4_v3(sds->obmat, vel); + normalize_v3(vel); + mul_v3_fl(vel, mag); + + voxelCenter[0] = sds->p0[0] + sds->cell_size[0] * ((float)(x + sds->res_min[0]) + 0.5f); + voxelCenter[1] = sds->p0[1] + sds->cell_size[1] * ((float)(y + sds->res_min[1]) + 0.5f); + voxelCenter[2] = sds->p0[2] + sds->cell_size[2] * ((float)(z + sds->res_min[2]) + 0.5f); + mul_m4_v3(sds->obmat, voxelCenter); + + pd_point_from_loc(data->scene, voxelCenter, vel, index, &epoint); + BKE_effectors_apply(data->effectors, NULL, sds->effector_weights, &epoint, retvel, NULL); + + /* convert retvel to local space */ + mag = len_v3(retvel); + mul_mat3_m4_v3(sds->imat, retvel); + normalize_v3(retvel); + mul_v3_fl(retvel, mag); + + // TODO dg - do in force! + data->force_x[index] = min_ff(max_ff(-1.0f, retvel[0] * 0.2f), 1.0f); + data->force_y[index] = min_ff(max_ff(-1.0f, retvel[1] * 0.2f), 1.0f); + data->force_z[index] = min_ff(max_ff(-1.0f, retvel[2] * 0.2f), 1.0f); + } + } } -static void update_effectors(Depsgraph *depsgraph, Scene *scene, Object *ob, SmokeDomainSettings *sds, float UNUSED(dt)) +static void update_effectors( + Depsgraph *depsgraph, Scene *scene, Object *ob, SmokeDomainSettings *sds, float UNUSED(dt)) { - ListBase *effectors; - /* make sure smoke flow influence is 0.0f */ - sds->effector_weights->weight[PFIELD_SMOKEFLOW] = 0.0f; - effectors = BKE_effectors_create(depsgraph, ob, NULL, sds->effector_weights); - - if (effectors) { - // precalculate wind forces - UpdateEffectorsData data; - data.scene = scene; - data.sds = sds; - data.effectors = effectors; - data.density = smoke_get_density(sds->fluid); - data.fuel = smoke_get_fuel(sds->fluid); - data.force_x = smoke_get_force_x(sds->fluid); - data.force_y = smoke_get_force_y(sds->fluid); - data.force_z = smoke_get_force_z(sds->fluid); - data.velocity_x = smoke_get_velocity_x(sds->fluid); - data.velocity_y = smoke_get_velocity_y(sds->fluid); - data.velocity_z = smoke_get_velocity_z(sds->fluid); - data.obstacle = smoke_get_obstacle(sds->fluid); - - ParallelRangeSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC; - BLI_task_parallel_range(0, sds->res[0], - &data, - update_effectors_task_cb, - &settings); - } - - BKE_effectors_free(effectors); + ListBase *effectors; + /* make sure smoke flow influence is 0.0f */ + sds->effector_weights->weight[PFIELD_SMOKEFLOW] = 0.0f; + effectors = BKE_effectors_create(depsgraph, ob, NULL, sds->effector_weights); + + if (effectors) { + // precalculate wind forces + UpdateEffectorsData data; + data.scene = scene; + data.sds = sds; + data.effectors = effectors; + data.density = smoke_get_density(sds->fluid); + data.fuel = smoke_get_fuel(sds->fluid); + data.force_x = smoke_get_force_x(sds->fluid); + data.force_y = smoke_get_force_y(sds->fluid); + data.force_z = smoke_get_force_z(sds->fluid); + data.velocity_x = smoke_get_velocity_x(sds->fluid); + data.velocity_y = smoke_get_velocity_y(sds->fluid); + data.velocity_z = smoke_get_velocity_z(sds->fluid); + data.obstacle = smoke_get_obstacle(sds->fluid); + + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC; + BLI_task_parallel_range(0, sds->res[0], &data, update_effectors_task_cb, &settings); + } + + BKE_effectors_free(effectors); } -static void step( - Depsgraph *depsgraph, - Scene *scene, Object *ob, SmokeModifierData *smd, Mesh *domain_me, float fps) +static void step(Depsgraph *depsgraph, + Scene *scene, + Object *ob, + SmokeModifierData *smd, + Mesh *domain_me, + float fps) { - SmokeDomainSettings *sds = smd->domain; - /* stability values copied from wturbulence.cpp */ - const int maxSubSteps = 25; - float maxVel; - // maxVel should be 1.5 (1.5 cell max movement) * dx (cell size) - - float dt; - float maxVelMag = 0.0f; - int totalSubsteps; - int substep = 0; - float dtSubdiv; - float gravity[3] = {0.0f, 0.0f, -1.0f}; - float gravity_mag; - - /* update object state */ - invert_m4_m4(sds->imat, ob->obmat); - copy_m4_m4(sds->obmat, ob->obmat); - smoke_set_domain_from_mesh(sds, ob, domain_me, (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) != 0); - - /* use global gravity if enabled */ - if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) { - copy_v3_v3(gravity, scene->physics_settings.gravity); - /* map default value to 1.0 */ - mul_v3_fl(gravity, 1.0f / 9.810f); - } - /* convert gravity to domain space */ - gravity_mag = len_v3(gravity); - mul_mat3_m4_v3(sds->imat, gravity); - normalize_v3(gravity); - mul_v3_fl(gravity, gravity_mag); - - /* adapt timestep for different framerates, dt = 0.1 is at 25fps */ - dt = DT_DEFAULT * (25.0f / fps); - // maximum timestep/"CFL" constraint: dt < 5.0 *dx / maxVel - maxVel = (sds->dx * 5.0f); - - maxVelMag = sqrtf(maxVelMag) * dt * sds->time_scale; - totalSubsteps = (int)((maxVelMag / maxVel) + 1.0f); /* always round up */ - totalSubsteps = (totalSubsteps < 1) ? 1 : totalSubsteps; - totalSubsteps = (totalSubsteps > maxSubSteps) ? maxSubSteps : totalSubsteps; - - /* Disable substeps for now, since it results in numerical instability */ - totalSubsteps = 1.0f; - - dtSubdiv = (float)dt / (float)totalSubsteps; - - // printf("totalSubsteps: %d, maxVelMag: %f, dt: %f\n", totalSubsteps, maxVelMag, dt); - - for (substep = 0; substep < totalSubsteps; substep++) - { - // calc animated obstacle velocities - update_flowsfluids(depsgraph, scene, ob, sds, dtSubdiv); - update_obstacles(depsgraph, ob, sds, dtSubdiv, substep, totalSubsteps); - - if (sds->total_cells > 1) { - update_effectors(depsgraph, scene, ob, sds, dtSubdiv); // DG TODO? problem --> uses forces instead of velocity, need to check how they need to be changed with variable dt - smoke_step(sds->fluid, gravity, dtSubdiv); - } - } + SmokeDomainSettings *sds = smd->domain; + /* stability values copied from wturbulence.cpp */ + const int maxSubSteps = 25; + float maxVel; + // maxVel should be 1.5 (1.5 cell max movement) * dx (cell size) + + float dt; + float maxVelMag = 0.0f; + int totalSubsteps; + int substep = 0; + float dtSubdiv; + float gravity[3] = {0.0f, 0.0f, -1.0f}; + float gravity_mag; + + /* update object state */ + invert_m4_m4(sds->imat, ob->obmat); + copy_m4_m4(sds->obmat, ob->obmat); + smoke_set_domain_from_mesh(sds, ob, domain_me, (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) != 0); + + /* use global gravity if enabled */ + if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) { + copy_v3_v3(gravity, scene->physics_settings.gravity); + /* map default value to 1.0 */ + mul_v3_fl(gravity, 1.0f / 9.810f); + } + /* convert gravity to domain space */ + gravity_mag = len_v3(gravity); + mul_mat3_m4_v3(sds->imat, gravity); + normalize_v3(gravity); + mul_v3_fl(gravity, gravity_mag); + + /* adapt timestep for different framerates, dt = 0.1 is at 25fps */ + dt = DT_DEFAULT * (25.0f / fps); + // maximum timestep/"CFL" constraint: dt < 5.0 *dx / maxVel + maxVel = (sds->dx * 5.0f); + + maxVelMag = sqrtf(maxVelMag) * dt * sds->time_scale; + totalSubsteps = (int)((maxVelMag / maxVel) + 1.0f); /* always round up */ + totalSubsteps = (totalSubsteps < 1) ? 1 : totalSubsteps; + totalSubsteps = (totalSubsteps > maxSubSteps) ? maxSubSteps : totalSubsteps; + + /* Disable substeps for now, since it results in numerical instability */ + totalSubsteps = 1.0f; + + dtSubdiv = (float)dt / (float)totalSubsteps; + + // printf("totalSubsteps: %d, maxVelMag: %f, dt: %f\n", totalSubsteps, maxVelMag, dt); + + for (substep = 0; substep < totalSubsteps; substep++) { + // calc animated obstacle velocities + update_flowsfluids(depsgraph, scene, ob, sds, dtSubdiv); + update_obstacles(depsgraph, ob, sds, dtSubdiv, substep, totalSubsteps); + + if (sds->total_cells > 1) { + update_effectors( + depsgraph, + scene, + ob, + sds, + dtSubdiv); // DG TODO? problem --> uses forces instead of velocity, need to check how they need to be changed with variable dt + smoke_step(sds->fluid, gravity, dtSubdiv); + } + } } static Mesh *createDomainGeometry(SmokeDomainSettings *sds, Object *ob) { - Mesh *result; - MVert *mverts; - MPoly *mpolys; - MLoop *mloops; - float min[3]; - float max[3]; - float *co; - MPoly *mp; - MLoop *ml; - - int num_verts = 8; - int num_faces = 6; - int i; - float ob_loc[3] = {0}; - float ob_cache_loc[3] = {0}; - - /* dont generate any mesh if there isnt any content */ - if (sds->total_cells <= 1) { - num_verts = 0; - num_faces = 0; - } - - result = BKE_mesh_new_nomain(num_verts, 0, 0, num_faces * 4, num_faces); - mverts = result->mvert; - mpolys = result->mpoly; - mloops = result->mloop; - - if (num_verts) { - /* volume bounds */ - madd_v3fl_v3fl_v3fl_v3i(min, sds->p0, sds->cell_size, sds->res_min); - madd_v3fl_v3fl_v3fl_v3i(max, sds->p0, sds->cell_size, sds->res_max); - - /* set vertices */ - /* top slab */ - co = mverts[0].co; co[0] = min[0]; co[1] = min[1]; co[2] = max[2]; - co = mverts[1].co; co[0] = max[0]; co[1] = min[1]; co[2] = max[2]; - co = mverts[2].co; co[0] = max[0]; co[1] = max[1]; co[2] = max[2]; - co = mverts[3].co; co[0] = min[0]; co[1] = max[1]; co[2] = max[2]; - /* bottom slab */ - co = mverts[4].co; co[0] = min[0]; co[1] = min[1]; co[2] = min[2]; - co = mverts[5].co; co[0] = max[0]; co[1] = min[1]; co[2] = min[2]; - co = mverts[6].co; co[0] = max[0]; co[1] = max[1]; co[2] = min[2]; - co = mverts[7].co; co[0] = min[0]; co[1] = max[1]; co[2] = min[2]; - - /* create faces */ - /* top */ - mp = &mpolys[0]; ml = &mloops[0 * 4]; mp->loopstart = 0 * 4; mp->totloop = 4; - ml[0].v = 0; ml[1].v = 1; ml[2].v = 2; ml[3].v = 3; - /* right */ - mp = &mpolys[1]; ml = &mloops[1 * 4]; mp->loopstart = 1 * 4; mp->totloop = 4; - ml[0].v = 2; ml[1].v = 1; ml[2].v = 5; ml[3].v = 6; - /* bottom */ - mp = &mpolys[2]; ml = &mloops[2 * 4]; mp->loopstart = 2 * 4; mp->totloop = 4; - ml[0].v = 7; ml[1].v = 6; ml[2].v = 5; ml[3].v = 4; - /* left */ - mp = &mpolys[3]; ml = &mloops[3 * 4]; mp->loopstart = 3 * 4; mp->totloop = 4; - ml[0].v = 0; ml[1].v = 3; ml[2].v = 7; ml[3].v = 4; - /* front */ - mp = &mpolys[4]; ml = &mloops[4 * 4]; mp->loopstart = 4 * 4; mp->totloop = 4; - ml[0].v = 3; ml[1].v = 2; ml[2].v = 6; ml[3].v = 7; - /* back */ - mp = &mpolys[5]; ml = &mloops[5 * 4]; mp->loopstart = 5 * 4; mp->totloop = 4; - ml[0].v = 1; ml[1].v = 0; ml[2].v = 4; ml[3].v = 5; - - /* calculate required shift to match domain's global position - * it was originally simulated at (if object moves without smoke step) */ - invert_m4_m4(ob->imat, ob->obmat); - mul_m4_v3(ob->obmat, ob_loc); - mul_m4_v3(sds->obmat, ob_cache_loc); - sub_v3_v3v3(sds->obj_shift_f, ob_cache_loc, ob_loc); - /* convert shift to local space and apply to vertices */ - mul_mat3_m4_v3(ob->imat, sds->obj_shift_f); - /* apply */ - for (i = 0; i < num_verts; i++) { - add_v3_v3(mverts[i].co, sds->obj_shift_f); - } - } - - BKE_mesh_calc_edges(result, false, false); - result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; - return result; + Mesh *result; + MVert *mverts; + MPoly *mpolys; + MLoop *mloops; + float min[3]; + float max[3]; + float *co; + MPoly *mp; + MLoop *ml; + + int num_verts = 8; + int num_faces = 6; + int i; + float ob_loc[3] = {0}; + float ob_cache_loc[3] = {0}; + + /* dont generate any mesh if there isnt any content */ + if (sds->total_cells <= 1) { + num_verts = 0; + num_faces = 0; + } + + result = BKE_mesh_new_nomain(num_verts, 0, 0, num_faces * 4, num_faces); + mverts = result->mvert; + mpolys = result->mpoly; + mloops = result->mloop; + + if (num_verts) { + /* volume bounds */ + madd_v3fl_v3fl_v3fl_v3i(min, sds->p0, sds->cell_size, sds->res_min); + madd_v3fl_v3fl_v3fl_v3i(max, sds->p0, sds->cell_size, sds->res_max); + + /* set vertices */ + /* top slab */ + co = mverts[0].co; + co[0] = min[0]; + co[1] = min[1]; + co[2] = max[2]; + co = mverts[1].co; + co[0] = max[0]; + co[1] = min[1]; + co[2] = max[2]; + co = mverts[2].co; + co[0] = max[0]; + co[1] = max[1]; + co[2] = max[2]; + co = mverts[3].co; + co[0] = min[0]; + co[1] = max[1]; + co[2] = max[2]; + /* bottom slab */ + co = mverts[4].co; + co[0] = min[0]; + co[1] = min[1]; + co[2] = min[2]; + co = mverts[5].co; + co[0] = max[0]; + co[1] = min[1]; + co[2] = min[2]; + co = mverts[6].co; + co[0] = max[0]; + co[1] = max[1]; + co[2] = min[2]; + co = mverts[7].co; + co[0] = min[0]; + co[1] = max[1]; + co[2] = min[2]; + + /* create faces */ + /* top */ + mp = &mpolys[0]; + ml = &mloops[0 * 4]; + mp->loopstart = 0 * 4; + mp->totloop = 4; + ml[0].v = 0; + ml[1].v = 1; + ml[2].v = 2; + ml[3].v = 3; + /* right */ + mp = &mpolys[1]; + ml = &mloops[1 * 4]; + mp->loopstart = 1 * 4; + mp->totloop = 4; + ml[0].v = 2; + ml[1].v = 1; + ml[2].v = 5; + ml[3].v = 6; + /* bottom */ + mp = &mpolys[2]; + ml = &mloops[2 * 4]; + mp->loopstart = 2 * 4; + mp->totloop = 4; + ml[0].v = 7; + ml[1].v = 6; + ml[2].v = 5; + ml[3].v = 4; + /* left */ + mp = &mpolys[3]; + ml = &mloops[3 * 4]; + mp->loopstart = 3 * 4; + mp->totloop = 4; + ml[0].v = 0; + ml[1].v = 3; + ml[2].v = 7; + ml[3].v = 4; + /* front */ + mp = &mpolys[4]; + ml = &mloops[4 * 4]; + mp->loopstart = 4 * 4; + mp->totloop = 4; + ml[0].v = 3; + ml[1].v = 2; + ml[2].v = 6; + ml[3].v = 7; + /* back */ + mp = &mpolys[5]; + ml = &mloops[5 * 4]; + mp->loopstart = 5 * 4; + mp->totloop = 4; + ml[0].v = 1; + ml[1].v = 0; + ml[2].v = 4; + ml[3].v = 5; + + /* calculate required shift to match domain's global position + * it was originally simulated at (if object moves without smoke step) */ + invert_m4_m4(ob->imat, ob->obmat); + mul_m4_v3(ob->obmat, ob_loc); + mul_m4_v3(sds->obmat, ob_cache_loc); + sub_v3_v3v3(sds->obj_shift_f, ob_cache_loc, ob_loc); + /* convert shift to local space and apply to vertices */ + mul_mat3_m4_v3(ob->imat, sds->obj_shift_f); + /* apply */ + for (i = 0; i < num_verts; i++) { + add_v3_v3(mverts[i].co, sds->obj_shift_f); + } + } + + BKE_mesh_calc_edges(result, false, false); + result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; + return result; } static void smokeModifier_process( - SmokeModifierData *smd, Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *me) + SmokeModifierData *smd, Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *me) { - const int scene_framenr = (int)DEG_get_ctime(depsgraph); - - if ((smd->type & MOD_SMOKE_TYPE_FLOW)) - { - if (scene_framenr >= smd->time) - smokeModifier_init(smd, ob, scene_framenr, me); - - if (smd->flow->mesh) BKE_id_free(NULL, smd->flow->mesh); - smd->flow->mesh = BKE_mesh_copy_for_eval(me, false); - - if (scene_framenr > smd->time) - { - smd->time = scene_framenr; - } - else if (scene_framenr < smd->time) - { - smd->time = scene_framenr; - smokeModifier_reset_ex(smd, false); - } - } - else if (smd->type & MOD_SMOKE_TYPE_COLL) - { - if (scene_framenr >= smd->time) - smokeModifier_init(smd, ob, scene_framenr, me); - - if (smd->coll) - { - if (smd->coll->mesh) - BKE_id_free(NULL, smd->coll->mesh); - - smd->coll->mesh = BKE_mesh_copy_for_eval(me, false); - } - - smd->time = scene_framenr; - if (scene_framenr < smd->time) - { - smokeModifier_reset_ex(smd, false); - } - } - else if (smd->type & MOD_SMOKE_TYPE_DOMAIN) - { - SmokeDomainSettings *sds = smd->domain; - PointCache *cache = NULL; - PTCacheID pid; - int startframe, endframe, framenr; - float timescale; - - framenr = scene_framenr; - - cache = sds->point_cache[0]; - BKE_ptcache_id_from_smoke(&pid, ob, smd); - BKE_ptcache_id_time(&pid, scene, framenr, &startframe, &endframe, ×cale); - - if (!smd->domain->fluid || framenr == startframe) - { - BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED); - smokeModifier_reset_ex(smd, false); - BKE_ptcache_validate(cache, framenr); - cache->flag &= ~PTCACHE_REDO_NEEDED; - } - - if (!smd->domain->fluid && (framenr != startframe) && (smd->domain->flags & MOD_SMOKE_FILE_LOAD) == 0 && (cache->flag & PTCACHE_BAKED) == 0) - return; - - smd->domain->flags &= ~MOD_SMOKE_FILE_LOAD; - CLAMP(framenr, startframe, endframe); - - /* If already viewing a pre/after frame, no need to reload */ - if ((smd->time == framenr) && (framenr != scene_framenr)) - return; - - if (smokeModifier_init(smd, ob, scene_framenr, me) == 0) - { - printf("bad smokeModifier_init\n"); - return; - } - - /* only calculate something when we advanced a single frame */ - /* don't simulate if viewing start frame, but scene frame is not real start frame */ - bool can_simulate = (framenr == (int)smd->time + 1) && (framenr == scene_framenr); - - /* try to read from cache */ - if (BKE_ptcache_read(&pid, (float)framenr, can_simulate) == PTCACHE_READ_EXACT) { - BKE_ptcache_validate(cache, framenr); - smd->time = framenr; - return; - } - - if (!can_simulate) - return; - -#ifdef DEBUG_TIME - double start = PIL_check_seconds_timer(); -#endif - - /* if on second frame, write cache for first frame */ - if ((int)smd->time == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact == 0)) { - BKE_ptcache_write(&pid, startframe); - } - - // set new time - smd->time = scene_framenr; - - /* do simulation */ - - // simulate the actual smoke (c++ code in intern/smoke) - // DG: interesting commenting this line + deactivating loading of noise files - if (framenr != startframe) - { - if (sds->flags & MOD_SMOKE_DISSOLVE) { - /* low res dissolve */ - smoke_dissolve(sds->fluid, sds->diss_speed, sds->flags & MOD_SMOKE_DISSOLVE_LOG); - /* high res dissolve */ - if (sds->wt) { - smoke_dissolve_wavelet(sds->wt, sds->diss_speed, sds->flags & MOD_SMOKE_DISSOLVE_LOG); - } - - } - - step(depsgraph, scene, ob, smd, me, scene->r.frs_sec / scene->r.frs_sec_base); - } - - // create shadows before writing cache so they get stored - smoke_calc_transparency(sds, DEG_get_evaluated_view_layer(depsgraph)); - - if (sds->wt && sds->total_cells > 1) { - smoke_turbulence_step(sds->wt, sds->fluid); - } - - BKE_ptcache_validate(cache, framenr); - if (framenr != startframe) - BKE_ptcache_write(&pid, framenr); - -#ifdef DEBUG_TIME - double end = PIL_check_seconds_timer(); - printf("Frame: %d, Time: %f\n\n", (int)smd->time, (float)(end - start)); -#endif - } + const int scene_framenr = (int)DEG_get_ctime(depsgraph); + + if ((smd->type & MOD_SMOKE_TYPE_FLOW)) { + if (scene_framenr >= smd->time) + smokeModifier_init(smd, ob, scene_framenr, me); + + if (smd->flow->mesh) + BKE_id_free(NULL, smd->flow->mesh); + smd->flow->mesh = BKE_mesh_copy_for_eval(me, false); + + if (scene_framenr > smd->time) { + smd->time = scene_framenr; + } + else if (scene_framenr < smd->time) { + smd->time = scene_framenr; + smokeModifier_reset_ex(smd, false); + } + } + else if (smd->type & MOD_SMOKE_TYPE_COLL) { + if (scene_framenr >= smd->time) + smokeModifier_init(smd, ob, scene_framenr, me); + + if (smd->coll) { + if (smd->coll->mesh) + BKE_id_free(NULL, smd->coll->mesh); + + smd->coll->mesh = BKE_mesh_copy_for_eval(me, false); + } + + smd->time = scene_framenr; + if (scene_framenr < smd->time) { + smokeModifier_reset_ex(smd, false); + } + } + else if (smd->type & MOD_SMOKE_TYPE_DOMAIN) { + SmokeDomainSettings *sds = smd->domain; + PointCache *cache = NULL; + PTCacheID pid; + int startframe, endframe, framenr; + float timescale; + + framenr = scene_framenr; + + cache = sds->point_cache[0]; + BKE_ptcache_id_from_smoke(&pid, ob, smd); + BKE_ptcache_id_time(&pid, scene, framenr, &startframe, &endframe, ×cale); + + if (!smd->domain->fluid || framenr == startframe) { + BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED); + smokeModifier_reset_ex(smd, false); + BKE_ptcache_validate(cache, framenr); + cache->flag &= ~PTCACHE_REDO_NEEDED; + } + + if (!smd->domain->fluid && (framenr != startframe) && + (smd->domain->flags & MOD_SMOKE_FILE_LOAD) == 0 && (cache->flag & PTCACHE_BAKED) == 0) + return; + + smd->domain->flags &= ~MOD_SMOKE_FILE_LOAD; + CLAMP(framenr, startframe, endframe); + + /* If already viewing a pre/after frame, no need to reload */ + if ((smd->time == framenr) && (framenr != scene_framenr)) + return; + + if (smokeModifier_init(smd, ob, scene_framenr, me) == 0) { + printf("bad smokeModifier_init\n"); + return; + } + + /* only calculate something when we advanced a single frame */ + /* don't simulate if viewing start frame, but scene frame is not real start frame */ + bool can_simulate = (framenr == (int)smd->time + 1) && (framenr == scene_framenr); + + /* try to read from cache */ + if (BKE_ptcache_read(&pid, (float)framenr, can_simulate) == PTCACHE_READ_EXACT) { + BKE_ptcache_validate(cache, framenr); + smd->time = framenr; + return; + } + + if (!can_simulate) + return; + +# ifdef DEBUG_TIME + double start = PIL_check_seconds_timer(); +# endif + + /* if on second frame, write cache for first frame */ + if ((int)smd->time == startframe && + (cache->flag & PTCACHE_OUTDATED || cache->last_exact == 0)) { + BKE_ptcache_write(&pid, startframe); + } + + // set new time + smd->time = scene_framenr; + + /* do simulation */ + + // simulate the actual smoke (c++ code in intern/smoke) + // DG: interesting commenting this line + deactivating loading of noise files + if (framenr != startframe) { + if (sds->flags & MOD_SMOKE_DISSOLVE) { + /* low res dissolve */ + smoke_dissolve(sds->fluid, sds->diss_speed, sds->flags & MOD_SMOKE_DISSOLVE_LOG); + /* high res dissolve */ + if (sds->wt) { + smoke_dissolve_wavelet(sds->wt, sds->diss_speed, sds->flags & MOD_SMOKE_DISSOLVE_LOG); + } + } + + step(depsgraph, scene, ob, smd, me, scene->r.frs_sec / scene->r.frs_sec_base); + } + + // create shadows before writing cache so they get stored + smoke_calc_transparency(sds, DEG_get_evaluated_view_layer(depsgraph)); + + if (sds->wt && sds->total_cells > 1) { + smoke_turbulence_step(sds->wt, sds->fluid); + } + + BKE_ptcache_validate(cache, framenr); + if (framenr != startframe) + BKE_ptcache_write(&pid, framenr); + +# ifdef DEBUG_TIME + double end = PIL_check_seconds_timer(); + printf("Frame: %d, Time: %f\n\n", (int)smd->time, (float)(end - start)); +# endif + } } struct Mesh *smokeModifier_do( - SmokeModifierData *smd, Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *me) + SmokeModifierData *smd, Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *me) { - /* lock so preview render does not read smoke data while it gets modified */ - if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) - BLI_rw_mutex_lock(smd->domain->fluid_mutex, THREAD_LOCK_WRITE); - - smokeModifier_process(smd, depsgraph, scene, ob, me); - - if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) - BLI_rw_mutex_unlock(smd->domain->fluid_mutex); - - /* return generated geometry for adaptive domain */ - Mesh *result; - if (smd->type & MOD_SMOKE_TYPE_DOMAIN && smd->domain && - smd->domain->flags & MOD_SMOKE_ADAPTIVE_DOMAIN && - smd->domain->base_res[0]) - { - result = createDomainGeometry(smd->domain, ob); - } - else { - result = BKE_mesh_copy_for_eval(me, false); - } - /* XXX This is really not a nice hack, but until root of the problem is understood, - * this should be an acceptable workaround I think. - * See T58492 for details on the issue. */ - result->texflag |= ME_AUTOSPACE; - return result; + /* lock so preview render does not read smoke data while it gets modified */ + if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) + BLI_rw_mutex_lock(smd->domain->fluid_mutex, THREAD_LOCK_WRITE); + + smokeModifier_process(smd, depsgraph, scene, ob, me); + + if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) + BLI_rw_mutex_unlock(smd->domain->fluid_mutex); + + /* return generated geometry for adaptive domain */ + Mesh *result; + if (smd->type & MOD_SMOKE_TYPE_DOMAIN && smd->domain && + smd->domain->flags & MOD_SMOKE_ADAPTIVE_DOMAIN && smd->domain->base_res[0]) { + result = createDomainGeometry(smd->domain, ob); + } + else { + result = BKE_mesh_copy_for_eval(me, false); + } + /* XXX This is really not a nice hack, but until root of the problem is understood, + * this should be an acceptable workaround I think. + * See T58492 for details on the issue. */ + result->texflag |= ME_AUTOSPACE; + return result; } -static float calc_voxel_transp(float *result, float *input, int res[3], int *pixel, float *tRay, float correct) +static float calc_voxel_transp( + float *result, float *input, int res[3], int *pixel, float *tRay, float correct) { - const size_t index = smoke_get_index(pixel[0], res[0], pixel[1], res[1], pixel[2]); + const size_t index = smoke_get_index(pixel[0], res[0], pixel[1], res[1], pixel[2]); - // T_ray *= T_vox - *tRay *= expf(input[index] * correct); + // T_ray *= T_vox + *tRay *= expf(input[index] * correct); - if (result[index] < 0.0f) - { - result[index] = *tRay; - } + if (result[index] < 0.0f) { + result[index] = *tRay; + } - return *tRay; + return *tRay; } -static void bresenham_linie_3D(int x1, int y1, int z1, int x2, int y2, int z2, float *tRay, bresenham_callback cb, float *result, float *input, int res[3], float correct) +static void bresenham_linie_3D(int x1, + int y1, + int z1, + int x2, + int y2, + int z2, + float *tRay, + bresenham_callback cb, + float *result, + float *input, + int res[3], + float correct) { - int dx, dy, dz, i, l, m, n, x_inc, y_inc, z_inc, err_1, err_2, dx2, dy2, dz2; - int pixel[3]; - - pixel[0] = x1; - pixel[1] = y1; - pixel[2] = z1; - - dx = x2 - x1; - dy = y2 - y1; - dz = z2 - z1; - - x_inc = (dx < 0) ? -1 : 1; - l = abs(dx); - y_inc = (dy < 0) ? -1 : 1; - m = abs(dy); - z_inc = (dz < 0) ? -1 : 1; - n = abs(dz); - dx2 = l << 1; - dy2 = m << 1; - dz2 = n << 1; - - if ((l >= m) && (l >= n)) { - err_1 = dy2 - l; - err_2 = dz2 - l; - for (i = 0; i < l; i++) { - if (cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON) - break; - if (err_1 > 0) { - pixel[1] += y_inc; - err_1 -= dx2; - } - if (err_2 > 0) { - pixel[2] += z_inc; - err_2 -= dx2; - } - err_1 += dy2; - err_2 += dz2; - pixel[0] += x_inc; - } - } - else if ((m >= l) && (m >= n)) { - err_1 = dx2 - m; - err_2 = dz2 - m; - for (i = 0; i < m; i++) { - if (cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON) - break; - if (err_1 > 0) { - pixel[0] += x_inc; - err_1 -= dy2; - } - if (err_2 > 0) { - pixel[2] += z_inc; - err_2 -= dy2; - } - err_1 += dx2; - err_2 += dz2; - pixel[1] += y_inc; - } - } - else { - err_1 = dy2 - n; - err_2 = dx2 - n; - for (i = 0; i < n; i++) { - if (cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON) - break; - if (err_1 > 0) { - pixel[1] += y_inc; - err_1 -= dz2; - } - if (err_2 > 0) { - pixel[0] += x_inc; - err_2 -= dz2; - } - err_1 += dy2; - err_2 += dx2; - pixel[2] += z_inc; - } - } - cb(result, input, res, pixel, tRay, correct); + int dx, dy, dz, i, l, m, n, x_inc, y_inc, z_inc, err_1, err_2, dx2, dy2, dz2; + int pixel[3]; + + pixel[0] = x1; + pixel[1] = y1; + pixel[2] = z1; + + dx = x2 - x1; + dy = y2 - y1; + dz = z2 - z1; + + x_inc = (dx < 0) ? -1 : 1; + l = abs(dx); + y_inc = (dy < 0) ? -1 : 1; + m = abs(dy); + z_inc = (dz < 0) ? -1 : 1; + n = abs(dz); + dx2 = l << 1; + dy2 = m << 1; + dz2 = n << 1; + + if ((l >= m) && (l >= n)) { + err_1 = dy2 - l; + err_2 = dz2 - l; + for (i = 0; i < l; i++) { + if (cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON) + break; + if (err_1 > 0) { + pixel[1] += y_inc; + err_1 -= dx2; + } + if (err_2 > 0) { + pixel[2] += z_inc; + err_2 -= dx2; + } + err_1 += dy2; + err_2 += dz2; + pixel[0] += x_inc; + } + } + else if ((m >= l) && (m >= n)) { + err_1 = dx2 - m; + err_2 = dz2 - m; + for (i = 0; i < m; i++) { + if (cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON) + break; + if (err_1 > 0) { + pixel[0] += x_inc; + err_1 -= dy2; + } + if (err_2 > 0) { + pixel[2] += z_inc; + err_2 -= dy2; + } + err_1 += dx2; + err_2 += dz2; + pixel[1] += y_inc; + } + } + else { + err_1 = dy2 - n; + err_2 = dx2 - n; + for (i = 0; i < n; i++) { + if (cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON) + break; + if (err_1 > 0) { + pixel[1] += y_inc; + err_1 -= dz2; + } + if (err_2 > 0) { + pixel[0] += x_inc; + err_2 -= dz2; + } + err_1 += dy2; + err_2 += dx2; + pixel[2] += z_inc; + } + } + cb(result, input, res, pixel, tRay, correct); } static void smoke_calc_transparency(SmokeDomainSettings *sds, ViewLayer *view_layer) { - float bv[6] = {0}; - float light[3]; - int a, z, slabsize = sds->res[0] * sds->res[1], size = sds->res[0] * sds->res[1] * sds->res[2]; - float *density = smoke_get_density(sds->fluid); - float correct = -7.0f * sds->dx; - - if (!get_light(view_layer, light)) return; - - /* convert light pos to sim cell space */ - mul_m4_v3(sds->imat, light); - light[0] = (light[0] - sds->p0[0]) / sds->cell_size[0] - 0.5f - (float)sds->res_min[0]; - light[1] = (light[1] - sds->p0[1]) / sds->cell_size[1] - 0.5f - (float)sds->res_min[1]; - light[2] = (light[2] - sds->p0[2]) / sds->cell_size[2] - 0.5f - (float)sds->res_min[2]; - - for (a = 0; a < size; a++) - sds->shadow[a] = -1.0f; - - /* calculate domain bounds in sim cell space */ - // 0,2,4 = 0.0f - bv[1] = (float)sds->res[0]; // x - bv[3] = (float)sds->res[1]; // y - bv[5] = (float)sds->res[2]; // z - - for (z = 0; z < sds->res[2]; z++) - { - size_t index = z * slabsize; - int x, y; - - for (y = 0; y < sds->res[1]; y++) - for (x = 0; x < sds->res[0]; x++, index++) - { - float voxelCenter[3]; - float pos[3]; - int cell[3]; - float tRay = 1.0; - - if (sds->shadow[index] >= 0.0f) - continue; - voxelCenter[0] = (float)x; - voxelCenter[1] = (float)y; - voxelCenter[2] = (float)z; - - // get starting cell (light pos) - if (BLI_bvhtree_bb_raycast(bv, light, voxelCenter, pos) > FLT_EPSILON) - { - // we're ouside -> use point on side of domain - cell[0] = (int)floor(pos[0]); - cell[1] = (int)floor(pos[1]); - cell[2] = (int)floor(pos[2]); - } - else { - // we're inside -> use light itself - cell[0] = (int)floor(light[0]); - cell[1] = (int)floor(light[1]); - cell[2] = (int)floor(light[2]); - } - /* clamp within grid bounds */ - CLAMP(cell[0], 0, sds->res[0] - 1); - CLAMP(cell[1], 0, sds->res[1] - 1); - CLAMP(cell[2], 0, sds->res[2] - 1); - - bresenham_linie_3D(cell[0], cell[1], cell[2], x, y, z, &tRay, calc_voxel_transp, sds->shadow, density, sds->res, correct); - - // convention -> from a RGBA float array, use G value for tRay - sds->shadow[index] = tRay; - } - } + float bv[6] = {0}; + float light[3]; + int a, z, slabsize = sds->res[0] * sds->res[1], size = sds->res[0] * sds->res[1] * sds->res[2]; + float *density = smoke_get_density(sds->fluid); + float correct = -7.0f * sds->dx; + + if (!get_light(view_layer, light)) + return; + + /* convert light pos to sim cell space */ + mul_m4_v3(sds->imat, light); + light[0] = (light[0] - sds->p0[0]) / sds->cell_size[0] - 0.5f - (float)sds->res_min[0]; + light[1] = (light[1] - sds->p0[1]) / sds->cell_size[1] - 0.5f - (float)sds->res_min[1]; + light[2] = (light[2] - sds->p0[2]) / sds->cell_size[2] - 0.5f - (float)sds->res_min[2]; + + for (a = 0; a < size; a++) + sds->shadow[a] = -1.0f; + + /* calculate domain bounds in sim cell space */ + // 0,2,4 = 0.0f + bv[1] = (float)sds->res[0]; // x + bv[3] = (float)sds->res[1]; // y + bv[5] = (float)sds->res[2]; // z + + for (z = 0; z < sds->res[2]; z++) { + size_t index = z * slabsize; + int x, y; + + for (y = 0; y < sds->res[1]; y++) + for (x = 0; x < sds->res[0]; x++, index++) { + float voxelCenter[3]; + float pos[3]; + int cell[3]; + float tRay = 1.0; + + if (sds->shadow[index] >= 0.0f) + continue; + voxelCenter[0] = (float)x; + voxelCenter[1] = (float)y; + voxelCenter[2] = (float)z; + + // get starting cell (light pos) + if (BLI_bvhtree_bb_raycast(bv, light, voxelCenter, pos) > FLT_EPSILON) { + // we're ouside -> use point on side of domain + cell[0] = (int)floor(pos[0]); + cell[1] = (int)floor(pos[1]); + cell[2] = (int)floor(pos[2]); + } + else { + // we're inside -> use light itself + cell[0] = (int)floor(light[0]); + cell[1] = (int)floor(light[1]); + cell[2] = (int)floor(light[2]); + } + /* clamp within grid bounds */ + CLAMP(cell[0], 0, sds->res[0] - 1); + CLAMP(cell[1], 0, sds->res[1] - 1); + CLAMP(cell[2], 0, sds->res[2] - 1); + + bresenham_linie_3D(cell[0], + cell[1], + cell[2], + x, + y, + z, + &tRay, + calc_voxel_transp, + sds->shadow, + density, + sds->res, + correct); + + // convention -> from a RGBA float array, use G value for tRay + sds->shadow[index] = tRay; + } + } } /* get smoke velocity and density at given coordinates * returns fluid density or -1.0f if outside domain. */ float BKE_smoke_get_velocity_at(struct Object *ob, float position[3], float velocity[3]) { - SmokeModifierData *smd = (SmokeModifierData *)modifiers_findByType(ob, eModifierType_Smoke); - zero_v3(velocity); - - if (smd && (smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain && smd->domain->fluid) { - SmokeDomainSettings *sds = smd->domain; - float time_mult = 25.f * DT_DEFAULT; - float vel_mag; - float *velX = smoke_get_velocity_x(sds->fluid); - float *velY = smoke_get_velocity_y(sds->fluid); - float *velZ = smoke_get_velocity_z(sds->fluid); - float density = 0.0f, fuel = 0.0f; - float pos[3]; - copy_v3_v3(pos, position); - smoke_pos_to_cell(sds, pos); - - /* check if point is outside domain max bounds */ - if (pos[0] < sds->res_min[0] || pos[1] < sds->res_min[1] || pos[2] < sds->res_min[2]) return -1.0f; - if (pos[0] > sds->res_max[0] || pos[1] > sds->res_max[1] || pos[2] > sds->res_max[2]) return -1.0f; - - /* map pos between 0.0 - 1.0 */ - pos[0] = (pos[0] - sds->res_min[0]) / ((float)sds->res[0]); - pos[1] = (pos[1] - sds->res_min[1]) / ((float)sds->res[1]); - pos[2] = (pos[2] - sds->res_min[2]) / ((float)sds->res[2]); - - - /* check if point is outside active area */ - if (smd->domain->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) { - if (pos[0] < 0.0f || pos[1] < 0.0f || pos[2] < 0.0f) return 0.0f; - if (pos[0] > 1.0f || pos[1] > 1.0f || pos[2] > 1.0f) return 0.0f; - } - - /* get interpolated velocity */ - velocity[0] = BLI_voxel_sample_trilinear(velX, sds->res, pos) * sds->global_size[0] * time_mult; - velocity[1] = BLI_voxel_sample_trilinear(velY, sds->res, pos) * sds->global_size[1] * time_mult; - velocity[2] = BLI_voxel_sample_trilinear(velZ, sds->res, pos) * sds->global_size[2] * time_mult; - - /* convert velocity direction to global space */ - vel_mag = len_v3(velocity); - mul_mat3_m4_v3(sds->obmat, velocity); - normalize_v3(velocity); - mul_v3_fl(velocity, vel_mag); - - /* use max value of fuel or smoke density */ - density = BLI_voxel_sample_trilinear(smoke_get_density(sds->fluid), sds->res, pos); - if (smoke_has_fuel(sds->fluid)) { - fuel = BLI_voxel_sample_trilinear(smoke_get_fuel(sds->fluid), sds->res, pos); - } - return MAX2(density, fuel); - } - return -1.0f; + SmokeModifierData *smd = (SmokeModifierData *)modifiers_findByType(ob, eModifierType_Smoke); + zero_v3(velocity); + + if (smd && (smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain && smd->domain->fluid) { + SmokeDomainSettings *sds = smd->domain; + float time_mult = 25.f * DT_DEFAULT; + float vel_mag; + float *velX = smoke_get_velocity_x(sds->fluid); + float *velY = smoke_get_velocity_y(sds->fluid); + float *velZ = smoke_get_velocity_z(sds->fluid); + float density = 0.0f, fuel = 0.0f; + float pos[3]; + copy_v3_v3(pos, position); + smoke_pos_to_cell(sds, pos); + + /* check if point is outside domain max bounds */ + if (pos[0] < sds->res_min[0] || pos[1] < sds->res_min[1] || pos[2] < sds->res_min[2]) + return -1.0f; + if (pos[0] > sds->res_max[0] || pos[1] > sds->res_max[1] || pos[2] > sds->res_max[2]) + return -1.0f; + + /* map pos between 0.0 - 1.0 */ + pos[0] = (pos[0] - sds->res_min[0]) / ((float)sds->res[0]); + pos[1] = (pos[1] - sds->res_min[1]) / ((float)sds->res[1]); + pos[2] = (pos[2] - sds->res_min[2]) / ((float)sds->res[2]); + + /* check if point is outside active area */ + if (smd->domain->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) { + if (pos[0] < 0.0f || pos[1] < 0.0f || pos[2] < 0.0f) + return 0.0f; + if (pos[0] > 1.0f || pos[1] > 1.0f || pos[2] > 1.0f) + return 0.0f; + } + + /* get interpolated velocity */ + velocity[0] = BLI_voxel_sample_trilinear(velX, sds->res, pos) * sds->global_size[0] * + time_mult; + velocity[1] = BLI_voxel_sample_trilinear(velY, sds->res, pos) * sds->global_size[1] * + time_mult; + velocity[2] = BLI_voxel_sample_trilinear(velZ, sds->res, pos) * sds->global_size[2] * + time_mult; + + /* convert velocity direction to global space */ + vel_mag = len_v3(velocity); + mul_mat3_m4_v3(sds->obmat, velocity); + normalize_v3(velocity); + mul_v3_fl(velocity, vel_mag); + + /* use max value of fuel or smoke density */ + density = BLI_voxel_sample_trilinear(smoke_get_density(sds->fluid), sds->res, pos); + if (smoke_has_fuel(sds->fluid)) { + fuel = BLI_voxel_sample_trilinear(smoke_get_fuel(sds->fluid), sds->res, pos); + } + return MAX2(density, fuel); + } + return -1.0f; } int BKE_smoke_get_data_flags(SmokeDomainSettings *sds) { - int flags = 0; - - if (sds->fluid) { - if (smoke_has_heat(sds->fluid)) - flags |= SM_ACTIVE_HEAT; - if (smoke_has_fuel(sds->fluid)) - flags |= SM_ACTIVE_FIRE; - if (smoke_has_colors(sds->fluid)) - flags |= SM_ACTIVE_COLORS; - } - - return flags; + int flags = 0; + + if (sds->fluid) { + if (smoke_has_heat(sds->fluid)) + flags |= SM_ACTIVE_HEAT; + if (smoke_has_fuel(sds->fluid)) + flags |= SM_ACTIVE_FIRE; + if (smoke_has_colors(sds->fluid)) + flags |= SM_ACTIVE_COLORS; + } + + return flags; } #endif /* WITH_SMOKE */ bool BKE_smoke_show_highres(Scene *scene, SmokeDomainSettings *sds) { - if ((sds->viewsettings & MOD_SMOKE_VIEW_SHOW_HIGHRES) == 0) { - return false; - } - if (scene->r.mode & R_SIMPLIFY) { - return !scene->r.simplify_smoke_ignore_highres; - } - return true; + if ((sds->viewsettings & MOD_SMOKE_VIEW_SHOW_HIGHRES) == 0) { + return false; + } + if (scene->r.mode & R_SIMPLIFY) { + return !scene->r.simplify_smoke_ignore_highres; + } + return true; } |