diff options
author | Aaron Carlisle <carlisle.b3d@gmail.com> | 2020-11-06 22:16:27 +0300 |
---|---|---|
committer | Aaron Carlisle <carlisle.b3d@gmail.com> | 2020-11-06 22:20:44 +0300 |
commit | d2c102060d4489aa1fd68f6c33df4ba9c4add78b (patch) | |
tree | 3a97430346da7902200cd0012de570026cc01207 /source/blender/render/intern/texture_pointdensity.c | |
parent | b3e71ee09802e84d52b7b7aed0c10cecba852431 (diff) |
Cleanup: Rename render texture files to texture_*
Diffstat (limited to 'source/blender/render/intern/texture_pointdensity.c')
-rw-r--r-- | source/blender/render/intern/texture_pointdensity.c | 984 |
1 files changed, 984 insertions, 0 deletions
diff --git a/source/blender/render/intern/texture_pointdensity.c b/source/blender/render/intern/texture_pointdensity.c new file mode 100644 index 00000000000..0e62eea5b11 --- /dev/null +++ b/source/blender/render/intern/texture_pointdensity.c @@ -0,0 +1,984 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + */ + +/** \file + * \ingroup render + */ + +#include <math.h> +#include <stdio.h> +#include <stdlib.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_kdopbvh.h" +#include "BLI_math.h" +#include "BLI_noise.h" +#include "BLI_task.h" +#include "BLI_utildefines.h" + +#include "BLT_translation.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" +#include "DNA_particle_types.h" +#include "DNA_texture_types.h" + +#include "BKE_colorband.h" +#include "BKE_colortools.h" +#include "BKE_deform.h" +#include "BKE_lattice.h" +#include "BKE_object.h" +#include "BKE_particle.h" +#include "BKE_scene.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + +#include "render_types.h" +#include "texture_common.h" + +#include "RE_render_ext.h" +#include "RE_shader_ext.h" + +static ThreadMutex sample_mutex = PTHREAD_MUTEX_INITIALIZER; + +static int point_data_used(PointDensity *pd) +{ + int pd_bitflag = 0; + + if (pd->source == TEX_PD_PSYS) { + if ((pd->falloff_type == TEX_PD_FALLOFF_PARTICLE_VEL) || + (pd->color_source == TEX_PD_COLOR_PARTVEL) || + (pd->color_source == TEX_PD_COLOR_PARTSPEED)) { + pd_bitflag |= POINT_DATA_VEL; + } + if ((pd->color_source == TEX_PD_COLOR_PARTAGE) || + (pd->falloff_type == TEX_PD_FALLOFF_PARTICLE_AGE)) { + pd_bitflag |= POINT_DATA_LIFE; + } + } + else if (pd->source == TEX_PD_OBJECT) { + if (ELEM(pd->ob_color_source, + TEX_PD_COLOR_VERTCOL, + TEX_PD_COLOR_VERTWEIGHT, + TEX_PD_COLOR_VERTNOR)) { + pd_bitflag |= POINT_DATA_COLOR; + } + } + + return pd_bitflag; +} + +static void point_data_pointers(PointDensity *pd, + float **r_data_velocity, + float **r_data_life, + float **r_data_color) +{ + const int data_used = point_data_used(pd); + const int totpoint = pd->totpoints; + float *data = pd->point_data; + int offset = 0; + + if (data_used & POINT_DATA_VEL) { + if (r_data_velocity) { + *r_data_velocity = data + offset; + } + offset += 3 * totpoint; + } + else { + if (r_data_velocity) { + *r_data_velocity = NULL; + } + } + + if (data_used & POINT_DATA_LIFE) { + if (r_data_life) { + *r_data_life = data + offset; + } + offset += totpoint; + } + else { + if (r_data_life) { + *r_data_life = NULL; + } + } + + if (data_used & POINT_DATA_COLOR) { + if (r_data_color) { + *r_data_color = data + offset; + } + offset += 3 * totpoint; + } + else { + if (r_data_color) { + *r_data_color = NULL; + } + } +} + +/* additional data stored alongside the point density BVH, + * accessible by point index number to retrieve other information + * such as particle velocity or lifetime */ +static void alloc_point_data(PointDensity *pd) +{ + const int totpoints = pd->totpoints; + int data_used = point_data_used(pd); + int data_size = 0; + + if (data_used & POINT_DATA_VEL) { + /* store 3 channels of velocity data */ + data_size += 3; + } + if (data_used & POINT_DATA_LIFE) { + /* store 1 channel of lifetime data */ + data_size += 1; + } + if (data_used & POINT_DATA_COLOR) { + /* store 3 channels of RGB data */ + data_size += 3; + } + + if (data_size) { + pd->point_data = MEM_callocN(sizeof(float) * data_size * totpoints, "particle point data"); + } +} + +static void pointdensity_cache_psys( + Depsgraph *depsgraph, Scene *scene, PointDensity *pd, Object *ob, ParticleSystem *psys) +{ + ParticleKey state; + ParticleCacheKey *cache; + ParticleSimulationData sim = {NULL}; + ParticleData *pa = NULL; + float cfra = BKE_scene_frame_get(scene); + int i /*, childexists*/ /* UNUSED */; + int total_particles; + int data_used; + float *data_vel, *data_life; + float partco[3]; + const bool use_render_params = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER); + + data_used = point_data_used(pd); + + if (!psys_check_enabled(ob, psys, use_render_params)) { + return; + } + + sim.depsgraph = depsgraph; + sim.scene = scene; + sim.ob = ob; + sim.psys = psys; + sim.psmd = psys_get_modifier(ob, psys); + + /* in case ob->imat isn't up-to-date */ + invert_m4_m4(ob->imat, ob->obmat); + + total_particles = psys->totpart + psys->totchild; + psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); + + pd->point_tree = BLI_bvhtree_new(total_particles, 0.0, 4, 6); + pd->totpoints = total_particles; + alloc_point_data(pd); + point_data_pointers(pd, &data_vel, &data_life, NULL); + +#if 0 /* UNUSED */ + if (psys->totchild > 0 && !(psys->part->draw & PART_DRAW_PARENT)) { + childexists = 1; + } +#endif + + for (i = 0, pa = psys->particles; i < total_particles; i++, pa++) { + + if (psys->part->type == PART_HAIR) { + /* hair particles */ + if (i < psys->totpart && psys->pathcache) { + cache = psys->pathcache[i]; + } + else if (i >= psys->totpart && psys->childcache) { + cache = psys->childcache[i - psys->totpart]; + } + else { + continue; + } + + cache += cache->segments; /* use endpoint */ + + copy_v3_v3(state.co, cache->co); + zero_v3(state.vel); + state.time = 0.0f; + } + else { + /* emitter particles */ + state.time = cfra; + + if (!psys_get_particle_state(&sim, i, &state, 0)) { + continue; + } + + if (data_used & POINT_DATA_LIFE) { + if (i < psys->totpart) { + state.time = (cfra - pa->time) / pa->lifetime; + } + else { + ChildParticle *cpa = (psys->child + i) - psys->totpart; + float pa_birthtime, pa_dietime; + + state.time = psys_get_child_time(psys, cpa, cfra, &pa_birthtime, &pa_dietime); + } + } + } + + copy_v3_v3(partco, state.co); + + if (pd->psys_cache_space == TEX_PD_OBJECTSPACE) { + mul_m4_v3(ob->imat, partco); + } + else if (pd->psys_cache_space == TEX_PD_OBJECTLOC) { + sub_v3_v3(partco, ob->loc); + } + else { + /* TEX_PD_WORLDSPACE */ + } + + BLI_bvhtree_insert(pd->point_tree, i, partco, 1); + + if (data_vel) { + data_vel[i * 3 + 0] = state.vel[0]; + data_vel[i * 3 + 1] = state.vel[1]; + data_vel[i * 3 + 2] = state.vel[2]; + } + if (data_life) { + data_life[i] = state.time; + } + } + + BLI_bvhtree_balance(pd->point_tree); + + if (psys->lattice_deform_data) { + BKE_lattice_deform_data_destroy(psys->lattice_deform_data); + psys->lattice_deform_data = NULL; + } +} + +static void pointdensity_cache_vertex_color(PointDensity *pd, + Object *UNUSED(ob), + Mesh *mesh, + float *data_color) +{ + const MLoop *mloop = mesh->mloop; + const int totloop = mesh->totloop; + const MLoopCol *mcol; + char layername[MAX_CUSTOMDATA_LAYER_NAME]; + int i; + + BLI_assert(data_color); + + if (!CustomData_has_layer(&mesh->ldata, CD_MLOOPCOL)) { + return; + } + CustomData_validate_layer_name(&mesh->ldata, CD_MLOOPCOL, pd->vertex_attribute_name, layername); + mcol = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPCOL, layername); + if (!mcol) { + return; + } + + /* Stores the number of MLoops using the same vertex, so we can normalize colors. */ + int *mcorners = MEM_callocN(sizeof(int) * pd->totpoints, "point density corner count"); + + for (i = 0; i < totloop; i++) { + int v = mloop[i].v; + + if (mcorners[v] == 0) { + rgb_uchar_to_float(&data_color[v * 3], &mcol[i].r); + } + else { + float col[3]; + rgb_uchar_to_float(col, &mcol[i].r); + add_v3_v3(&data_color[v * 3], col); + } + + ++mcorners[v]; + } + + /* Normalize colors by averaging over mcorners. + * All the corners share the same vertex, ie. occupy the same point in space. + */ + for (i = 0; i < pd->totpoints; i++) { + if (mcorners[i] > 0) { + mul_v3_fl(&data_color[i * 3], 1.0f / mcorners[i]); + } + } + + MEM_freeN(mcorners); +} + +static void pointdensity_cache_vertex_weight(PointDensity *pd, + Object *ob, + Mesh *mesh, + float *data_color) +{ + const int totvert = mesh->totvert; + const MDeformVert *mdef, *dv; + int mdef_index; + int i; + + BLI_assert(data_color); + + mdef = CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT); + if (!mdef) { + return; + } + mdef_index = BKE_object_defgroup_name_index(ob, pd->vertex_attribute_name); + if (mdef_index < 0) { + mdef_index = ob->actdef - 1; + } + if (mdef_index < 0) { + return; + } + + for (i = 0, dv = mdef; i < totvert; i++, dv++, data_color += 3) { + MDeformWeight *dw; + int j; + + for (j = 0, dw = dv->dw; j < dv->totweight; j++, dw++) { + if (dw->def_nr == mdef_index) { + copy_v3_fl(data_color, dw->weight); + break; + } + } + } +} + +static void pointdensity_cache_vertex_normal(PointDensity *pd, + Object *UNUSED(ob), + Mesh *mesh, + float *data_color) +{ + MVert *mvert = mesh->mvert, *mv; + int i; + + BLI_assert(data_color); + + for (i = 0, mv = mvert; i < pd->totpoints; i++, mv++, data_color += 3) { + normal_short_to_float_v3(data_color, mv->no); + } +} + +static void pointdensity_cache_object(PointDensity *pd, Object *ob) +{ + float *data_color; + int i; + MVert *mvert = NULL, *mv; + Mesh *mesh = ob->data; + +#if 0 /* UNUSED */ + CustomData_MeshMasks mask = CD_MASK_BAREMESH; + mask.fmask |= CD_MASK_MTFACE | CD_MASK_MCOL; + switch (pd->ob_color_source) { + case TEX_PD_COLOR_VERTCOL: + mask.lmask |= CD_MASK_MLOOPCOL; + break; + case TEX_PD_COLOR_VERTWEIGHT: + mask.vmask |= CD_MASK_MDEFORMVERT; + break; + } +#endif + + mvert = mesh->mvert; /* local object space */ + pd->totpoints = mesh->totvert; + if (pd->totpoints == 0) { + return; + } + + pd->point_tree = BLI_bvhtree_new(pd->totpoints, 0.0, 4, 6); + alloc_point_data(pd); + point_data_pointers(pd, NULL, NULL, &data_color); + + for (i = 0, mv = mvert; i < pd->totpoints; i++, mv++) { + float co[3]; + + copy_v3_v3(co, mv->co); + + switch (pd->ob_cache_space) { + case TEX_PD_OBJECTSPACE: + break; + case TEX_PD_OBJECTLOC: + mul_m4_v3(ob->obmat, co); + sub_v3_v3(co, ob->loc); + break; + case TEX_PD_WORLDSPACE: + default: + mul_m4_v3(ob->obmat, co); + break; + } + + BLI_bvhtree_insert(pd->point_tree, i, co, 1); + } + + switch (pd->ob_color_source) { + case TEX_PD_COLOR_VERTCOL: + pointdensity_cache_vertex_color(pd, ob, mesh, data_color); + break; + case TEX_PD_COLOR_VERTWEIGHT: + pointdensity_cache_vertex_weight(pd, ob, mesh, data_color); + break; + case TEX_PD_COLOR_VERTNOR: + pointdensity_cache_vertex_normal(pd, ob, mesh, data_color); + break; + } + + BLI_bvhtree_balance(pd->point_tree); +} + +static void cache_pointdensity(Depsgraph *depsgraph, Scene *scene, PointDensity *pd) +{ + if (pd == NULL) { + return; + } + + if (pd->point_tree) { + BLI_bvhtree_free(pd->point_tree); + pd->point_tree = NULL; + } + + if (pd->source == TEX_PD_PSYS) { + Object *ob = pd->object; + ParticleSystem *psys; + + if (!ob || !pd->psys) { + return; + } + + psys = BLI_findlink(&ob->particlesystem, pd->psys - 1); + if (!psys) { + return; + } + + pointdensity_cache_psys(depsgraph, scene, pd, ob, psys); + } + else if (pd->source == TEX_PD_OBJECT) { + Object *ob = pd->object; + if (ob && ob->type == OB_MESH) { + pointdensity_cache_object(pd, ob); + } + } +} + +static void free_pointdensity(PointDensity *pd) +{ + if (pd == NULL) { + return; + } + + if (pd->point_tree) { + BLI_bvhtree_free(pd->point_tree); + pd->point_tree = NULL; + } + + if (pd->point_data) { + MEM_freeN(pd->point_data); + pd->point_data = NULL; + } + pd->totpoints = 0; +} + +typedef struct PointDensityRangeData { + float *density; + float squared_radius; + float *point_data_life; + float *point_data_velocity; + float *point_data_color; + float *vec; + float *col; + float softness; + short falloff_type; + short noise_influence; + float *age; + struct CurveMapping *density_curve; + float velscale; +} PointDensityRangeData; + +static float density_falloff(PointDensityRangeData *pdr, int index, float squared_dist) +{ + const float dist = (pdr->squared_radius - squared_dist) / pdr->squared_radius * 0.5f; + float density = 0.0f; + + switch (pdr->falloff_type) { + case TEX_PD_FALLOFF_STD: + density = dist; + break; + case TEX_PD_FALLOFF_SMOOTH: + density = 3.0f * dist * dist - 2.0f * dist * dist * dist; + break; + case TEX_PD_FALLOFF_SOFT: + density = pow(dist, pdr->softness); + break; + case TEX_PD_FALLOFF_CONSTANT: + density = pdr->squared_radius; + break; + case TEX_PD_FALLOFF_ROOT: + density = sqrtf(dist); + break; + case TEX_PD_FALLOFF_PARTICLE_AGE: + if (pdr->point_data_life) { + density = dist * MIN2(pdr->point_data_life[index], 1.0f); + } + else { + density = dist; + } + break; + case TEX_PD_FALLOFF_PARTICLE_VEL: + if (pdr->point_data_velocity) { + density = dist * len_v3(&pdr->point_data_velocity[index * 3]) * pdr->velscale; + } + else { + density = dist; + } + break; + } + + if (pdr->density_curve && dist != 0.0f) { + BKE_curvemapping_init(pdr->density_curve); + density = BKE_curvemapping_evaluateF(pdr->density_curve, 0, density / dist) * dist; + } + + return density; +} + +static void accum_density(void *userdata, int index, const float co[3], float squared_dist) +{ + PointDensityRangeData *pdr = (PointDensityRangeData *)userdata; + float density = 0.0f; + + UNUSED_VARS(co); + + if (pdr->point_data_velocity) { + pdr->vec[0] += pdr->point_data_velocity[index * 3 + 0]; // * density; + pdr->vec[1] += pdr->point_data_velocity[index * 3 + 1]; // * density; + pdr->vec[2] += pdr->point_data_velocity[index * 3 + 2]; // * density; + } + if (pdr->point_data_life) { + *pdr->age += pdr->point_data_life[index]; // * density; + } + if (pdr->point_data_color) { + add_v3_v3(pdr->col, &pdr->point_data_color[index * 3]); // * density; + } + + density = density_falloff(pdr, index, squared_dist); + + *pdr->density += density; +} + +static void init_pointdensityrangedata(PointDensity *pd, + PointDensityRangeData *pdr, + float *density, + float *vec, + float *age, + float *col, + struct CurveMapping *density_curve, + float velscale) +{ + pdr->squared_radius = pd->radius * pd->radius; + pdr->density = density; + pdr->falloff_type = pd->falloff_type; + pdr->vec = vec; + pdr->age = age; + pdr->col = col; + pdr->softness = pd->falloff_softness; + pdr->noise_influence = pd->noise_influence; + point_data_pointers( + pd, &pdr->point_data_velocity, &pdr->point_data_life, &pdr->point_data_color); + pdr->density_curve = density_curve; + pdr->velscale = velscale; +} + +static int pointdensity(PointDensity *pd, + const float texvec[3], + TexResult *texres, + float r_vec[3], + float *r_age, + float r_col[3]) +{ + int retval = TEX_INT; + PointDensityRangeData pdr; + float density = 0.0f, age = 0.0f; + float vec[3] = {0.0f, 0.0f, 0.0f}, col[3] = {0.0f, 0.0f, 0.0f}, co[3]; + float turb, noise_fac; + int num = 0; + + texres->tin = 0.0f; + + init_pointdensityrangedata(pd, + &pdr, + &density, + vec, + &age, + col, + (pd->flag & TEX_PD_FALLOFF_CURVE ? pd->falloff_curve : NULL), + pd->falloff_speed_scale * 0.001f); + noise_fac = pd->noise_fac * 0.5f; /* better default */ + + copy_v3_v3(co, texvec); + + if (point_data_used(pd)) { + /* does a BVH lookup to find accumulated density and additional point data * + * stores particle velocity vector in 'vec', and particle lifetime in 'time' */ + num = BLI_bvhtree_range_query(pd->point_tree, co, pd->radius, accum_density, &pdr); + if (num > 0) { + age /= num; + mul_v3_fl(vec, 1.0f / num); + mul_v3_fl(col, 1.0f / num); + } + + /* reset */ + density = 0.0f; + zero_v3(vec); + zero_v3(col); + } + + if (pd->flag & TEX_PD_TURBULENCE) { + turb = BLI_noise_generic_turbulence(pd->noise_size, + texvec[0] + vec[0], + texvec[1] + vec[1], + texvec[2] + vec[2], + pd->noise_depth, + 0, + pd->noise_basis); + + turb -= 0.5f; /* re-center 0.0-1.0 range around 0 to prevent offsetting result */ + + /* now we have an offset coordinate to use for the density lookup */ + co[0] = texvec[0] + noise_fac * turb; + co[1] = texvec[1] + noise_fac * turb; + co[2] = texvec[2] + noise_fac * turb; + } + + /* BVH query with the potentially perturbed coordinates */ + num = BLI_bvhtree_range_query(pd->point_tree, co, pd->radius, accum_density, &pdr); + if (num > 0) { + age /= num; + mul_v3_fl(vec, 1.0f / num); + mul_v3_fl(col, 1.0f / num); + } + + texres->tin = density; + if (r_age != NULL) { + *r_age = age; + } + if (r_vec != NULL) { + copy_v3_v3(r_vec, vec); + } + if (r_col != NULL) { + copy_v3_v3(r_col, col); + } + + return retval; +} + +static void pointdensity_color( + PointDensity *pd, TexResult *texres, float age, const float vec[3], const float col[3]) +{ + texres->tr = texres->tg = texres->tb = texres->ta = 1.0f; + + if (pd->source == TEX_PD_PSYS) { + float rgba[4]; + + switch (pd->color_source) { + case TEX_PD_COLOR_PARTAGE: + if (pd->coba) { + if (BKE_colorband_evaluate(pd->coba, age, rgba)) { + texres->talpha = true; + copy_v3_v3(&texres->tr, rgba); + texres->tin *= rgba[3]; + texres->ta = texres->tin; + } + } + break; + case TEX_PD_COLOR_PARTSPEED: { + float speed = len_v3(vec) * pd->speed_scale; + + if (pd->coba) { + if (BKE_colorband_evaluate(pd->coba, speed, rgba)) { + texres->talpha = true; + copy_v3_v3(&texres->tr, rgba); + texres->tin *= rgba[3]; + texres->ta = texres->tin; + } + } + break; + } + case TEX_PD_COLOR_PARTVEL: + texres->talpha = true; + mul_v3_v3fl(&texres->tr, vec, pd->speed_scale); + texres->ta = texres->tin; + break; + case TEX_PD_COLOR_CONSTANT: + default: + break; + } + } + else { + float rgba[4]; + + switch (pd->ob_color_source) { + case TEX_PD_COLOR_VERTCOL: + texres->talpha = true; + copy_v3_v3(&texres->tr, col); + texres->ta = texres->tin; + break; + case TEX_PD_COLOR_VERTWEIGHT: + texres->talpha = true; + if (pd->coba && BKE_colorband_evaluate(pd->coba, col[0], rgba)) { + copy_v3_v3(&texres->tr, rgba); + texres->tin *= rgba[3]; + } + else { + copy_v3_v3(&texres->tr, col); + } + texres->ta = texres->tin; + break; + case TEX_PD_COLOR_VERTNOR: + texres->talpha = true; + copy_v3_v3(&texres->tr, col); + texres->ta = texres->tin; + break; + case TEX_PD_COLOR_CONSTANT: + default: + break; + } + } +} + +static void sample_dummy_point_density(int resolution, float *values) +{ + memset(values, 0, sizeof(float[4]) * resolution * resolution * resolution); +} + +static void particle_system_minmax(Depsgraph *depsgraph, + Scene *scene, + Object *object, + ParticleSystem *psys, + float radius, + float min[3], + float max[3]) +{ + const float size[3] = {radius, radius, radius}; + const float cfra = BKE_scene_frame_get(scene); + ParticleSettings *part = psys->part; + ParticleSimulationData sim = {NULL}; + ParticleData *pa = NULL; + int i; + int total_particles; + float mat[4][4], imat[4][4]; + + INIT_MINMAX(min, max); + if (part->type == PART_HAIR) { + /* TODO(sergey): Not supported currently. */ + return; + } + + unit_m4(mat); + + sim.depsgraph = depsgraph; + sim.scene = scene; + sim.ob = object; + sim.psys = psys; + sim.psmd = psys_get_modifier(object, psys); + + invert_m4_m4(imat, object->obmat); + total_particles = psys->totpart + psys->totchild; + psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); + + for (i = 0, pa = psys->particles; i < total_particles; i++, pa++) { + float co_object[3], co_min[3], co_max[3]; + ParticleKey state; + state.time = cfra; + if (!psys_get_particle_state(&sim, i, &state, 0)) { + continue; + } + mul_v3_m4v3(co_object, imat, state.co); + sub_v3_v3v3(co_min, co_object, size); + add_v3_v3v3(co_max, co_object, size); + minmax_v3v3_v3(min, max, co_min); + minmax_v3v3_v3(min, max, co_max); + } + + if (psys->lattice_deform_data) { + BKE_lattice_deform_data_destroy(psys->lattice_deform_data); + psys->lattice_deform_data = NULL; + } +} + +void RE_point_density_cache(struct Depsgraph *depsgraph, PointDensity *pd) +{ + Scene *scene = DEG_get_evaluated_scene(depsgraph); + + /* Same matrices/resolution as dupli_render_particle_set(). */ + BLI_mutex_lock(&sample_mutex); + cache_pointdensity(depsgraph, scene, pd); + BLI_mutex_unlock(&sample_mutex); +} + +void RE_point_density_minmax(struct Depsgraph *depsgraph, + struct PointDensity *pd, + float r_min[3], + float r_max[3]) +{ + Scene *scene = DEG_get_evaluated_scene(depsgraph); + Object *object = pd->object; + if (object == NULL) { + zero_v3(r_min); + zero_v3(r_max); + return; + } + if (pd->source == TEX_PD_PSYS) { + ParticleSystem *psys; + + if (pd->psys == 0) { + zero_v3(r_min); + zero_v3(r_max); + return; + } + psys = BLI_findlink(&object->particlesystem, pd->psys - 1); + if (psys == NULL) { + zero_v3(r_min); + zero_v3(r_max); + return; + } + + particle_system_minmax(depsgraph, scene, object, psys, pd->radius, r_min, r_max); + } + else { + const float radius[3] = {pd->radius, pd->radius, pd->radius}; + BoundBox *bb = BKE_object_boundbox_get(object); + + if (bb != NULL) { + BLI_assert((bb->flag & BOUNDBOX_DIRTY) == 0); + copy_v3_v3(r_min, bb->vec[0]); + copy_v3_v3(r_max, bb->vec[6]); + /* Adjust texture space to include density points on the boundaries. */ + sub_v3_v3(r_min, radius); + add_v3_v3(r_max, radius); + } + else { + zero_v3(r_min); + zero_v3(r_max); + } + } +} + +typedef struct SampleCallbackData { + PointDensity *pd; + int resolution; + float *min, *dim; + float *values; +} SampleCallbackData; + +static void point_density_sample_func(void *__restrict data_v, + const int iter, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + SampleCallbackData *data = (SampleCallbackData *)data_v; + + const int resolution = data->resolution; + const int resolution2 = resolution * resolution; + const float *min = data->min, *dim = data->dim; + PointDensity *pd = data->pd; + float *values = data->values; + + if (!pd || !pd->point_tree) { + return; + } + + size_t z = (size_t)iter; + for (size_t y = 0; y < resolution; y++) { + for (size_t x = 0; x < resolution; x++) { + size_t index = z * resolution2 + y * resolution + x; + float texvec[3]; + float age, vec[3], col[3]; + TexResult texres; + + copy_v3_v3(texvec, min); + texvec[0] += dim[0] * (float)x / (float)resolution; + texvec[1] += dim[1] * (float)y / (float)resolution; + texvec[2] += dim[2] * (float)z / (float)resolution; + + pointdensity(pd, texvec, &texres, vec, &age, col); + pointdensity_color(pd, &texres, age, vec, col); + + copy_v3_v3(&values[index * 4 + 0], &texres.tr); + values[index * 4 + 3] = texres.tin; + } + } +} + +/* NOTE 1: Requires RE_point_density_cache() to be called first. + * NOTE 2: Frees point density structure after sampling. + */ +void RE_point_density_sample(Depsgraph *depsgraph, + PointDensity *pd, + const int resolution, + float *values) +{ + Object *object = pd->object; + float min[3], max[3], dim[3]; + + /* TODO(sergey): Implement some sort of assert() that point density + * was cached already. + */ + + if (object == NULL) { + sample_dummy_point_density(resolution, values); + return; + } + + BLI_mutex_lock(&sample_mutex); + RE_point_density_minmax(depsgraph, pd, min, max); + BLI_mutex_unlock(&sample_mutex); + sub_v3_v3v3(dim, max, min); + if (dim[0] <= 0.0f || dim[1] <= 0.0f || dim[2] <= 0.0f) { + sample_dummy_point_density(resolution, values); + return; + } + + SampleCallbackData data; + data.pd = pd; + data.resolution = resolution; + data.min = min; + data.dim = dim; + data.values = values; + TaskParallelSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (resolution > 32); + BLI_task_parallel_range(0, resolution, &data, point_density_sample_func, &settings); + + free_pointdensity(pd); +} + +void RE_point_density_free(struct PointDensity *pd) +{ + free_pointdensity(pd); +} + +void RE_point_density_fix_linking(void) +{ +} |