Fix T47038: Particles in Particle Edit Mode get added in completely wrong location.
[blender.git] / source / blender / render / intern / source / pointdensity.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * Contributors: Matt Ebb
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/render/intern/source/pointdensity.c
27  *  \ingroup render
28  */
29
30
31 #include <math.h>
32 #include <stdlib.h>
33 #include <stdio.h>
34
35 #include "MEM_guardedalloc.h"
36
37 #include "BLI_math.h"
38 #include "BLI_blenlib.h"
39 #include "BLI_noise.h"
40 #include "BLI_kdopbvh.h"
41 #include "BLI_utildefines.h"
42
43 #include "BLT_translation.h"
44
45 #include "BKE_DerivedMesh.h"
46 #include "BKE_lattice.h"
47 #include "BKE_main.h"
48 #include "BKE_object.h"
49 #include "BKE_particle.h"
50 #include "BKE_scene.h"
51 #include "BKE_texture.h"
52 #include "BKE_colortools.h"
53
54 #include "DNA_meshdata_types.h"
55 #include "DNA_texture_types.h"
56 #include "DNA_particle_types.h"
57
58 #include "render_types.h"
59 #include "texture.h"
60 #include "pointdensity.h"
61
62 #include "RE_render_ext.h"
63
64 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
65 /* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
66 /* only to be used here in this file, it's for speed */
67 extern struct Render R;
68 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
69
70 static ThreadMutex sample_mutex = PTHREAD_MUTEX_INITIALIZER;
71
72 static int point_data_used(PointDensity *pd)
73 {
74         int pd_bitflag = 0;
75
76         if (pd->source == TEX_PD_PSYS) {
77                 if ((pd->noise_influence == TEX_PD_NOISE_VEL) ||
78                     (pd->falloff_type == TEX_PD_FALLOFF_PARTICLE_VEL) ||
79                     (pd->color_source == TEX_PD_COLOR_PARTVEL) ||
80                     (pd->color_source == TEX_PD_COLOR_PARTSPEED))
81                 {
82                         pd_bitflag |= POINT_DATA_VEL;
83                 }
84                 if ((pd->noise_influence == TEX_PD_NOISE_AGE) ||
85                     (pd->color_source == TEX_PD_COLOR_PARTAGE) ||
86                     (pd->falloff_type == TEX_PD_FALLOFF_PARTICLE_AGE))
87                 {
88                         pd_bitflag |= POINT_DATA_LIFE;
89                 }
90         }
91
92         return pd_bitflag;
93 }
94
95
96 /* additional data stored alongside the point density BVH,
97  * accessible by point index number to retrieve other information
98  * such as particle velocity or lifetime */
99 static void alloc_point_data(PointDensity *pd, int total_particles, int point_data_used)
100 {
101         int data_size = 0;
102
103         if (point_data_used & POINT_DATA_VEL) {
104                 /* store 3 channels of velocity data */
105                 data_size += 3;
106         }
107         if (point_data_used & POINT_DATA_LIFE) {
108                 /* store 1 channel of lifetime data */
109                 data_size += 1;
110         }
111
112         if (data_size) {
113                 pd->point_data = MEM_mallocN(sizeof(float) * data_size * total_particles,
114                                              "particle point data");
115         }
116 }
117
118 static void pointdensity_cache_psys(Scene *scene,
119                                     PointDensity *pd,
120                                     Object *ob,
121                                     ParticleSystem *psys,
122                                     float viewmat[4][4],
123                                     float winmat[4][4],
124                                     int winx, int winy,
125                                     const bool use_render_params)
126 {
127         DerivedMesh *dm;
128         ParticleKey state;
129         ParticleCacheKey *cache;
130         ParticleSimulationData sim = {NULL};
131         ParticleData *pa = NULL;
132         float cfra = BKE_scene_frame_get(scene);
133         int i /*, childexists*/ /* UNUSED */;
134         int total_particles, offset = 0;
135         int data_used = point_data_used(pd);
136         float partco[3];
137
138         /* init everything */
139         if (!psys || !ob || !pd) {
140                 return;
141         }
142
143         /* Just to create a valid rendering context for particles */
144         if (use_render_params) {
145                 psys_render_set(ob, psys, viewmat, winmat, winx, winy, 0);
146         }
147
148         if (use_render_params) {
149                 dm = mesh_create_derived_render(scene,
150                                                 ob,
151                                                 CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL);
152         }
153         else {
154                 dm = mesh_get_derived_final(scene,
155                                             ob,
156                                             CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL);
157         }
158
159         if ( !psys_check_enabled(ob, psys)) {
160                 psys_render_restore(scene, ob, psys);
161                 return;
162         }
163
164         sim.scene = scene;
165         sim.ob = ob;
166         sim.psys = psys;
167         sim.psmd = psys_get_modifier(ob, psys);
168
169         /* in case ob->imat isn't up-to-date */
170         invert_m4_m4(ob->imat, ob->obmat);
171
172         total_particles = psys->totpart + psys->totchild;
173         psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
174
175         pd->point_tree = BLI_bvhtree_new(total_particles, 0.0, 4, 6);
176         alloc_point_data(pd, total_particles, data_used);
177         pd->totpoints = total_particles;
178         if (data_used & POINT_DATA_VEL) {
179                 offset = pd->totpoints * 3;
180         }
181
182 #if 0 /* UNUSED */
183         if (psys->totchild > 0 && !(psys->part->draw & PART_DRAW_PARENT))
184                 childexists = 1;
185 #endif
186
187         for (i = 0, pa = psys->particles; i < total_particles; i++, pa++) {
188
189                 if (psys->part->type == PART_HAIR) {
190                         /* hair particles */
191                         if (i < psys->totpart && psys->pathcache)
192                                 cache = psys->pathcache[i];
193                         else if (i >= psys->totpart && psys->childcache)
194                                 cache = psys->childcache[i - psys->totpart];
195                         else
196                                 continue;
197
198                         cache += cache->segments; /* use endpoint */
199
200                         copy_v3_v3(state.co, cache->co);
201                         zero_v3(state.vel);
202                         state.time = 0.0f;
203                 }
204                 else {
205                         /* emitter particles */
206                         state.time = cfra;
207
208                         if (!psys_get_particle_state(&sim, i, &state, 0))
209                                 continue;
210
211                         if (data_used & POINT_DATA_LIFE) {
212                                 if (i < psys->totpart) {
213                                         state.time = (cfra - pa->time) / pa->lifetime;
214                                 }
215                                 else {
216                                         ChildParticle *cpa = (psys->child + i) - psys->totpart;
217                                         float pa_birthtime, pa_dietime;
218
219                                         state.time = psys_get_child_time(psys, cpa, cfra, &pa_birthtime, &pa_dietime);
220                                 }
221                         }
222                 }
223
224                 copy_v3_v3(partco, state.co);
225
226                 if (pd->psys_cache_space == TEX_PD_OBJECTSPACE)
227                         mul_m4_v3(ob->imat, partco);
228                 else if (pd->psys_cache_space == TEX_PD_OBJECTLOC) {
229                         sub_v3_v3(partco, ob->loc);
230                 }
231                 else {
232                         /* TEX_PD_WORLDSPACE */
233                 }
234
235                 BLI_bvhtree_insert(pd->point_tree, i, partco, 1);
236
237                 if (data_used & POINT_DATA_VEL) {
238                         pd->point_data[i * 3 + 0] = state.vel[0];
239                         pd->point_data[i * 3 + 1] = state.vel[1];
240                         pd->point_data[i * 3 + 2] = state.vel[2];
241                 }
242                 if (data_used & POINT_DATA_LIFE) {
243                         pd->point_data[offset + i] = state.time;
244                 }
245         }
246
247         BLI_bvhtree_balance(pd->point_tree);
248         dm->release(dm);
249
250         if (psys->lattice_deform_data) {
251                 end_latt_deform(psys->lattice_deform_data);
252                 psys->lattice_deform_data = NULL;
253         }
254
255         if (use_render_params) {
256                 psys_render_restore(scene, ob, psys);
257         }
258 }
259
260
261 static void pointdensity_cache_object(Scene *scene,
262                                       PointDensity *pd,
263                                       Object *ob,
264                                       const bool use_render_params)
265 {
266         int i;
267         DerivedMesh *dm;
268         MVert *mvert = NULL;
269
270         if (use_render_params) {
271                 dm = mesh_create_derived_render(scene,
272                                                 ob,
273                                                 CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL);
274         }
275         else {
276                 dm = mesh_get_derived_final(scene,
277                                             ob,
278                                             CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL);
279
280         }
281         mvert = dm->getVertArray(dm);   /* local object space */
282
283         pd->totpoints = dm->getNumVerts(dm);
284         if (pd->totpoints == 0) {
285                 return;
286         }
287
288         pd->point_tree = BLI_bvhtree_new(pd->totpoints, 0.0, 4, 6);
289
290         for (i = 0; i < pd->totpoints; i++, mvert++) {
291                 float co[3];
292
293                 copy_v3_v3(co, mvert->co);
294
295                 switch (pd->ob_cache_space) {
296                         case TEX_PD_OBJECTSPACE:
297                                 break;
298                         case TEX_PD_OBJECTLOC:
299                                 mul_m4_v3(ob->obmat, co);
300                                 sub_v3_v3(co, ob->loc);
301                                 break;
302                         case TEX_PD_WORLDSPACE:
303                         default:
304                                 mul_m4_v3(ob->obmat, co);
305                                 break;
306                 }
307
308                 BLI_bvhtree_insert(pd->point_tree, i, co, 1);
309         }
310
311         BLI_bvhtree_balance(pd->point_tree);
312         dm->release(dm);
313
314 }
315
316 static void cache_pointdensity_ex(Scene *scene,
317                                   PointDensity *pd,
318                                   float viewmat[4][4],
319                                   float winmat[4][4],
320                                   int winx, int winy,
321                                   const bool use_render_params)
322 {
323         if (pd == NULL) {
324                 return;
325         }
326
327         if (pd->point_tree) {
328                 BLI_bvhtree_free(pd->point_tree);
329                 pd->point_tree = NULL;
330         }
331
332         if (pd->source == TEX_PD_PSYS) {
333                 Object *ob = pd->object;
334                 ParticleSystem *psys;
335
336                 if (!ob || !pd->psys) {
337                         return;
338                 }
339
340                 psys = BLI_findlink(&ob->particlesystem, pd->psys - 1);
341                 if (!psys) {
342                         return;
343                 }
344
345                 pointdensity_cache_psys(scene,
346                                         pd,
347                                         ob,
348                                         psys,
349                                         viewmat, winmat,
350                                         winx, winy,
351                                         use_render_params);
352         }
353         else if (pd->source == TEX_PD_OBJECT) {
354                 Object *ob = pd->object;
355                 if (ob && ob->type == OB_MESH)
356                         pointdensity_cache_object(scene, pd, ob, use_render_params);
357         }
358 }
359
360 void cache_pointdensity(Render *re, PointDensity *pd)
361 {
362         cache_pointdensity_ex(re->scene,
363                               pd,
364                               re->viewmat, re->winmat,
365                               re->winx, re->winy,
366                               true);
367 }
368
369 void free_pointdensity(PointDensity *pd)
370 {
371         if (pd == NULL) {
372                 return;
373         }
374
375         if (pd->point_tree) {
376                 BLI_bvhtree_free(pd->point_tree);
377                 pd->point_tree = NULL;
378         }
379
380         if (pd->point_data) {
381                 MEM_freeN(pd->point_data);
382                 pd->point_data = NULL;
383         }
384         pd->totpoints = 0;
385 }
386
387 void make_pointdensities(Render *re)
388 {
389         Tex *tex;
390
391         if (re->scene->r.scemode & R_BUTS_PREVIEW) {
392                 return;
393         }
394
395         re->i.infostr = IFACE_("Caching Point Densities");
396         re->stats_draw(re->sdh, &re->i);
397
398         for (tex = re->main->tex.first; tex != NULL; tex = tex->id.next) {
399                 if (tex->id.us && tex->type == TEX_POINTDENSITY) {
400                         cache_pointdensity(re, tex->pd);
401                 }
402         }
403
404         re->i.infostr = NULL;
405         re->stats_draw(re->sdh, &re->i);
406 }
407
408 void free_pointdensities(Render *re)
409 {
410         Tex *tex;
411
412         if (re->scene->r.scemode & R_BUTS_PREVIEW)
413                 return;
414
415         for (tex = re->main->tex.first; tex != NULL; tex = tex->id.next) {
416                 if (tex->id.us && tex->type == TEX_POINTDENSITY) {
417                         free_pointdensity(tex->pd);
418                 }
419         }
420 }
421
422 typedef struct PointDensityRangeData {
423         float *density;
424         float squared_radius;
425         const float *point_data;
426         float *vec;
427         float softness;
428         short falloff_type;
429         short noise_influence;
430         float *age;
431         int point_data_used;
432         int offset;
433         struct CurveMapping *density_curve;
434         float velscale;
435 } PointDensityRangeData;
436
437 static void accum_density(void *userdata, int index, float squared_dist)
438 {
439         PointDensityRangeData *pdr = (PointDensityRangeData *)userdata;
440         const float dist = (pdr->squared_radius - squared_dist) / pdr->squared_radius * 0.5f;
441         float density = 0.0f;
442
443         if (pdr->point_data_used & POINT_DATA_VEL) {
444                 pdr->vec[0] += pdr->point_data[index * 3 + 0]; // * density;
445                 pdr->vec[1] += pdr->point_data[index * 3 + 1]; // * density;
446                 pdr->vec[2] += pdr->point_data[index * 3 + 2]; // * density;
447         }
448         if (pdr->point_data_used & POINT_DATA_LIFE) {
449                 *pdr->age += pdr->point_data[pdr->offset + index]; // * density;
450         }
451
452         if (pdr->falloff_type == TEX_PD_FALLOFF_STD)
453                 density = dist;
454         else if (pdr->falloff_type == TEX_PD_FALLOFF_SMOOTH)
455                 density = 3.0f * dist * dist - 2.0f * dist * dist * dist;
456         else if (pdr->falloff_type == TEX_PD_FALLOFF_SOFT)
457                 density = pow(dist, pdr->softness);
458         else if (pdr->falloff_type == TEX_PD_FALLOFF_CONSTANT)
459                 density = pdr->squared_radius;
460         else if (pdr->falloff_type == TEX_PD_FALLOFF_ROOT)
461                 density = sqrtf(dist);
462         else if (pdr->falloff_type == TEX_PD_FALLOFF_PARTICLE_AGE) {
463                 if (pdr->point_data_used & POINT_DATA_LIFE)
464                         density = dist * MIN2(pdr->point_data[pdr->offset + index], 1.0f);
465                 else
466                         density = dist;
467         }
468         else if (pdr->falloff_type == TEX_PD_FALLOFF_PARTICLE_VEL) {
469                 if (pdr->point_data_used & POINT_DATA_VEL)
470                         density = dist * len_v3(pdr->point_data + index * 3) * pdr->velscale;
471                 else
472                         density = dist;
473         }
474
475         if (pdr->density_curve && dist != 0.0f) {
476                 curvemapping_initialize(pdr->density_curve);
477                 density = curvemapping_evaluateF(pdr->density_curve, 0, density / dist) * dist;
478         }
479
480         *pdr->density += density;
481 }
482
483
484 static void init_pointdensityrangedata(PointDensity *pd, PointDensityRangeData *pdr,
485         float *density, float *vec, float *age, struct CurveMapping *density_curve, float velscale)
486 {
487         pdr->squared_radius = pd->radius * pd->radius;
488         pdr->density = density;
489         pdr->point_data = pd->point_data;
490         pdr->falloff_type = pd->falloff_type;
491         pdr->vec = vec;
492         pdr->age = age;
493         pdr->softness = pd->falloff_softness;
494         pdr->noise_influence = pd->noise_influence;
495         pdr->point_data_used = point_data_used(pd);
496         pdr->offset = (pdr->point_data_used & POINT_DATA_VEL) ? pd->totpoints * 3 : 0;
497         pdr->density_curve = density_curve;
498         pdr->velscale = velscale;
499 }
500
501
502 static int pointdensity(PointDensity *pd,
503                         const float texvec[3],
504                         TexResult *texres,
505                         float *r_age,
506                         float r_vec[3])
507 {
508         int retval = TEX_INT;
509         PointDensityRangeData pdr;
510         float density = 0.0f, age = 0.0f, time = 0.0f;
511         float vec[3] = {0.0f, 0.0f, 0.0f}, co[3];
512         float turb, noise_fac;
513         int num = 0;
514
515         texres->tin = 0.0f;
516
517         if ((!pd) || (!pd->point_tree))
518                 return 0;
519
520         init_pointdensityrangedata(pd, &pdr, &density, vec, &age,
521                 (pd->flag & TEX_PD_FALLOFF_CURVE ? pd->falloff_curve : NULL),
522                 pd->falloff_speed_scale * 0.001f);
523         noise_fac = pd->noise_fac * 0.5f;       /* better default */
524
525         copy_v3_v3(co, texvec);
526
527         if (point_data_used(pd)) {
528                 /* does a BVH lookup to find accumulated density and additional point data *
529                  * stores particle velocity vector in 'vec', and particle lifetime in 'time' */
530                 num = BLI_bvhtree_range_query(pd->point_tree, co, pd->radius, accum_density, &pdr);
531                 if (num > 0) {
532                         age /= num;
533                         mul_v3_fl(vec, 1.0f / num);
534                 }
535
536                 /* reset */
537                 density = vec[0] = vec[1] = vec[2] = 0.0f;
538         }
539
540         if (pd->flag & TEX_PD_TURBULENCE) {
541
542                 if (pd->noise_influence == TEX_PD_NOISE_AGE) {
543                         turb = BLI_gTurbulence(pd->noise_size, texvec[0] + age, texvec[1] + age, texvec[2] + age,
544                                                pd->noise_depth, 0, pd->noise_basis);
545                 }
546                 else if (pd->noise_influence == TEX_PD_NOISE_TIME) {
547                         time = R.r.cfra / (float)R.r.efra;
548                         turb = BLI_gTurbulence(pd->noise_size, texvec[0] + time, texvec[1] + time, texvec[2] + time,
549                                                pd->noise_depth, 0, pd->noise_basis);
550                         //turb = BLI_turbulence(pd->noise_size, texvec[0]+time, texvec[1]+time, texvec[2]+time, pd->noise_depth);
551                 }
552                 else {
553                         turb = BLI_gTurbulence(pd->noise_size, texvec[0] + vec[0], texvec[1] + vec[1], texvec[2] + vec[2],
554                                                pd->noise_depth, 0, pd->noise_basis);
555                 }
556
557                 turb -= 0.5f;   /* re-center 0.0-1.0 range around 0 to prevent offsetting result */
558
559                 /* now we have an offset coordinate to use for the density lookup */
560                 co[0] = texvec[0] + noise_fac * turb;
561                 co[1] = texvec[1] + noise_fac * turb;
562                 co[2] = texvec[2] + noise_fac * turb;
563         }
564
565         /* BVH query with the potentially perturbed coordinates */
566         num = BLI_bvhtree_range_query(pd->point_tree, co, pd->radius, accum_density, &pdr);
567         if (num > 0) {
568                 age /= num;
569                 mul_v3_fl(vec, 1.0f / num);
570         }
571
572         texres->tin = density;
573         if (r_age != NULL) {
574                 *r_age = age;
575         }
576         if (r_vec != NULL) {
577                 copy_v3_v3(r_vec, vec);
578         }
579
580         return retval;
581 }
582
583 static int pointdensity_color(PointDensity *pd, TexResult *texres, float age, const float vec[3])
584 {
585         int retval = 0;
586         float col[4];
587
588         retval |= TEX_RGB;
589
590         switch (pd->color_source) {
591                 case TEX_PD_COLOR_PARTAGE:
592                         if (pd->coba) {
593                                 if (do_colorband(pd->coba, age, col)) {
594                                         texres->talpha = true;
595                                         copy_v3_v3(&texres->tr, col);
596                                         texres->tin *= col[3];
597                                         texres->ta = texres->tin;
598                                 }
599                         }
600                         break;
601                 case TEX_PD_COLOR_PARTSPEED:
602                 {
603                         float speed = len_v3(vec) * pd->speed_scale;
604
605                         if (pd->coba) {
606                                 if (do_colorband(pd->coba, speed, col)) {
607                                         texres->talpha = true;
608                                         copy_v3_v3(&texres->tr, col);
609                                         texres->tin *= col[3];
610                                         texres->ta = texres->tin;
611                                 }
612                         }
613                         break;
614                 }
615                 case TEX_PD_COLOR_PARTVEL:
616                         texres->talpha = true;
617                         mul_v3_v3fl(&texres->tr, vec, pd->speed_scale);
618                         texres->ta = texres->tin;
619                         break;
620                 case TEX_PD_COLOR_CONSTANT:
621                 default:
622                         texres->tr = texres->tg = texres->tb = texres->ta = 1.0f;
623                         break;
624         }
625         
626         return retval;
627 }
628
629 int pointdensitytex(Tex *tex, const float texvec[3], TexResult *texres)
630 {
631         PointDensity *pd = tex->pd;
632         float age = 0.0f;
633         float vec[3] = {0.0f, 0.0f, 0.0f};
634         int retval = pointdensity(pd, texvec, texres, &age, vec);
635
636         BRICONT;
637
638         if (pd->color_source == TEX_PD_COLOR_CONSTANT)
639                 return retval;
640
641         retval |= pointdensity_color(pd, texres, age, vec);
642         BRICONTRGB;
643
644         return retval;
645
646 #if 0
647         if (texres->nor!=NULL) {
648                 texres->nor[0] = texres->nor[1] = texres->nor[2] = 0.0f;
649         }
650 #endif
651 }
652
653 static void sample_dummy_point_density(int resolution, float *values)
654 {
655         memset(values, 0, sizeof(float) * 4 * resolution * resolution * resolution);
656 }
657
658 static void particle_system_minmax(Scene *scene,
659                                    Object *object,
660                                    ParticleSystem *psys,
661                                    float radius,
662                                    const bool use_render_params,
663                                    float min[3], float max[3])
664 {
665         const float size[3] = {radius, radius, radius};
666         const float cfra = BKE_scene_frame_get(scene);
667         ParticleSettings *part = psys->part;
668         ParticleSimulationData sim = {NULL};
669         ParticleData *pa = NULL;
670         int i;
671         int total_particles;
672         float mat[4][4], imat[4][4];
673
674         INIT_MINMAX(min, max);
675         if (part->type == PART_HAIR) {
676                 /* TOOD(sergey): Not supported currently. */
677                 return;
678         }
679
680         unit_m4(mat);
681         if (use_render_params) {
682                 psys_render_set(object, psys, mat, mat, 1, 1, 0);
683         }
684
685         sim.scene = scene;
686         sim.ob = object;
687         sim.psys = psys;
688         sim.psmd = psys_get_modifier(object, psys);
689
690         invert_m4_m4(imat, object->obmat);
691         total_particles = psys->totpart + psys->totchild;
692         psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
693
694         for (i = 0, pa = psys->particles; i < total_particles; i++, pa++) {
695                 float co_object[3], co_min[3], co_max[3];
696                 ParticleKey state;
697                 state.time = cfra;
698                 if (!psys_get_particle_state(&sim, i, &state, 0)) {
699                         continue;
700                 }
701                 mul_v3_m4v3(co_object, imat, state.co);
702                 sub_v3_v3v3(co_min, co_object, size);
703                 add_v3_v3v3(co_max, co_object, size);
704                 minmax_v3v3_v3(min, max, co_min);
705                 minmax_v3v3_v3(min, max, co_max);
706         }
707
708         if (psys->lattice_deform_data) {
709                 end_latt_deform(psys->lattice_deform_data);
710                 psys->lattice_deform_data = NULL;
711         }
712
713         if (use_render_params) {
714                 psys_render_restore(scene, object, psys);
715         }
716 }
717
718 void RE_cache_point_density(Scene *scene,
719                             PointDensity *pd,
720                             const bool use_render_params)
721 {
722         float mat[4][4];
723         /* Same matricies/resolution as dupli_render_particle_set(). */
724         unit_m4(mat);
725         BLI_mutex_lock(&sample_mutex);
726         cache_pointdensity_ex(scene, pd, mat, mat, 1, 1, use_render_params);
727         BLI_mutex_unlock(&sample_mutex);
728 }
729
730 /* NOTE 1: Requires RE_cache_point_density() to be called first.
731  * NOTE 2: Frees point density structure after sampling.
732  */
733 void RE_sample_point_density(Scene *scene,
734                              PointDensity *pd,
735                              const int resolution,
736                              const bool use_render_params,
737                              float *values)
738 {
739         const size_t resolution2 = resolution * resolution;
740         Object *object = pd->object;
741         size_t x, y, z;
742         float min[3], max[3], dim[3];
743
744         /* TODO(sergey): Implement some sort of assert() that point density
745          * was cached already.
746          */
747
748         if (object == NULL) {
749                 sample_dummy_point_density(resolution, values);
750                 return;
751         }
752
753         if (pd->source == TEX_PD_PSYS) {
754                 ParticleSystem *psys;
755                 if (pd->psys == 0) {
756                         sample_dummy_point_density(resolution, values);
757                         return;
758                 }
759                 psys = BLI_findlink(&object->particlesystem, pd->psys - 1);
760                 if (psys == NULL) {
761                         sample_dummy_point_density(resolution, values);
762                         return;
763                 }
764                 particle_system_minmax(scene,
765                                        object,
766                                        psys,
767                                        pd->radius,
768                                        use_render_params,
769                                        min, max);
770         }
771         else {
772                 float radius[3] = {pd->radius, pd->radius, pd->radius};
773                 float *loc, *size;
774                 BKE_object_obdata_texspace_get(pd->object, NULL, &loc, &size, NULL);
775                 sub_v3_v3v3(min, loc, size);
776                 add_v3_v3v3(max, loc, size);
777                 /* Adjust texture space to include density points on the boundaries. */
778                 sub_v3_v3(min, radius);
779                 add_v3_v3(max, radius);
780         }
781
782         sub_v3_v3v3(dim, max, min);
783         if (dim[0] <= 0.0f || dim[1] <= 0.0f || dim[2] <= 0.0f) {
784                 sample_dummy_point_density(resolution, values);
785                 return;
786         }
787
788         BLI_mutex_lock(&sample_mutex);
789         for (z = 0; z < resolution; ++z) {
790                 for (y = 0; y < resolution; ++y) {
791                         for (x = 0; x < resolution; ++x) {
792                                 size_t index = z * resolution2 + y * resolution + x;
793                                 float texvec[3];
794                                 float age, vec[3];
795                                 TexResult texres;
796
797                                 copy_v3_v3(texvec, min);
798                                 texvec[0] += dim[0] * (float)x / (float)resolution;
799                                 texvec[1] += dim[1] * (float)y / (float)resolution;
800                                 texvec[2] += dim[2] * (float)z / (float)resolution;
801
802                                 pointdensity(pd, texvec, &texres, &age, vec);
803                                 pointdensity_color(pd, &texres, age, vec);
804
805                                 copy_v3_v3(&values[index*4 + 0], &texres.tr);
806                                 values[index*4 + 3] = texres.tin;
807                         }
808                 }
809         }
810         free_pointdensity(pd);
811         BLI_mutex_unlock(&sample_mutex);
812 }