Merge with trunk r39750
[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_kdopbvh.h"
40 #include "BLI_utildefines.h"
41
42 #include "BKE_DerivedMesh.h"
43 #include "BKE_global.h"
44 #include "BKE_lattice.h"
45 #include "BKE_main.h"
46 #include "BKE_object.h"
47 #include "BKE_particle.h"
48 #include "BKE_scene.h"
49 #include "BKE_texture.h"
50 #include "BKE_colortools.h"
51
52 #include "DNA_meshdata_types.h"
53 #include "DNA_texture_types.h"
54 #include "DNA_particle_types.h"
55
56 #include "render_types.h"
57 #include "renderdatabase.h"
58 #include "texture.h"
59 #include "pointdensity.h"
60
61 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
62 /* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
63 /* only to be used here in this file, it's for speed */
64 extern struct Render R;
65 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
66
67
68 static int point_data_used(PointDensity *pd)
69 {
70         int pd_bitflag = 0;
71         
72         if (pd->source == TEX_PD_PSYS) {
73                 if ((pd->noise_influence == TEX_PD_NOISE_VEL) || (pd->falloff_type == TEX_PD_FALLOFF_PARTICLE_VEL) || (pd->color_source == TEX_PD_COLOR_PARTVEL) || (pd->color_source == TEX_PD_COLOR_PARTSPEED))
74                         pd_bitflag |= POINT_DATA_VEL;
75                 if ((pd->noise_influence == TEX_PD_NOISE_AGE) || (pd->color_source == TEX_PD_COLOR_PARTAGE) || (pd->falloff_type == TEX_PD_FALLOFF_PARTICLE_AGE)) 
76                         pd_bitflag |= POINT_DATA_LIFE;
77         }
78                 
79         return pd_bitflag;
80 }
81
82
83 /* additional data stored alongside the point density BVH, 
84  * accessible by point index number to retrieve other information 
85  * such as particle velocity or lifetime */
86 static void alloc_point_data(PointDensity *pd, int total_particles, int point_data_used)
87 {
88         int data_size = 0;
89         
90         if (point_data_used & POINT_DATA_VEL) {
91                 /* store 3 channels of velocity data */
92                 data_size += 3;
93         }
94         if (point_data_used & POINT_DATA_LIFE) {
95                 /* store 1 channel of lifetime data */
96                 data_size += 1;
97         }
98
99         if (data_size)
100                 pd->point_data = MEM_mallocN(sizeof(float)*data_size*total_particles, "particle point data");
101 }
102
103 static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, ParticleSystem *psys)
104 {
105         DerivedMesh* dm;
106         ParticleKey state;
107         ParticleSimulationData sim= {NULL};
108         ParticleData *pa=NULL;
109         float cfra = BKE_curframe(re->scene);
110         int i, childexists;
111         int total_particles, offset=0;
112         int data_used = point_data_used(pd);
113         float partco[3];
114         float obview[4][4];
115         
116         /* init everything */
117         if (!psys || !ob || !pd) return;
118
119         mul_m4_m4m4(obview, re->viewinv, ob->obmat);
120         
121         /* Just to create a valid rendering context for particles */
122         psys_render_set(ob, psys, re->viewmat, re->winmat, re->winx, re->winy, 0);
123         
124         dm = mesh_create_derived_render(re->scene, ob,CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL);
125         
126         if ( !psys_check_enabled(ob, psys)) {
127                 psys_render_restore(ob, psys);
128                 return;
129         }
130         
131         sim.scene= re->scene;
132         sim.ob= ob;
133         sim.psys= psys;
134
135         /* in case ob->imat isn't up-to-date */
136         invert_m4_m4(ob->imat, ob->obmat);
137         
138         total_particles = psys->totpart+psys->totchild;
139         psys->lattice=psys_get_lattice(&sim);
140         
141         pd->point_tree = BLI_bvhtree_new(total_particles, 0.0, 4, 6);
142         alloc_point_data(pd, total_particles, data_used);
143         pd->totpoints = total_particles;
144         if (data_used & POINT_DATA_VEL) offset = pd->totpoints*3;
145         
146         if (psys->totchild > 0 && !(psys->part->draw & PART_DRAW_PARENT))
147                 childexists = 1;
148         
149         for (i=0, pa=psys->particles; i < total_particles; i++, pa++) {
150
151                 state.time = cfra;
152                 if(psys_get_particle_state(&sim, i, &state, 0)) {
153                         
154                         VECCOPY(partco, state.co);
155                         
156                         if (pd->psys_cache_space == TEX_PD_OBJECTSPACE)
157                                 mul_m4_v3(ob->imat, partco);
158                         else if (pd->psys_cache_space == TEX_PD_OBJECTLOC) {
159                                 sub_v3_v3(partco, ob->loc);
160                         } else {
161                                 /* TEX_PD_WORLDSPACE */
162                         }
163                         
164                         BLI_bvhtree_insert(pd->point_tree, i, partco, 1);
165                         
166                         if (data_used & POINT_DATA_VEL) {
167                                 pd->point_data[i*3 + 0] = state.vel[0];
168                                 pd->point_data[i*3 + 1] = state.vel[1];
169                                 pd->point_data[i*3 + 2] = state.vel[2];
170                         } 
171                         if (data_used & POINT_DATA_LIFE) {
172                                 float pa_time;
173                                 
174                                 if (i < psys->totpart) {
175                                         pa_time = (cfra - pa->time)/pa->lifetime;
176                                 } else {
177                                         ChildParticle *cpa= (psys->child + i) - psys->totpart;
178                                         float pa_birthtime, pa_dietime;
179                                         
180                                         pa_time = psys_get_child_time(psys, cpa, cfra, &pa_birthtime, &pa_dietime);
181                                 }
182                                 
183                                 pd->point_data[offset + i] = pa_time;
184                                 
185                         }
186                 }
187         }
188         
189         BLI_bvhtree_balance(pd->point_tree);
190         dm->release(dm);
191         
192         if(psys->lattice){
193                 end_latt_deform(psys->lattice);
194                 psys->lattice=0;
195         }
196         
197         psys_render_restore(ob, psys);
198 }
199
200
201 static void pointdensity_cache_object(Render *re, PointDensity *pd, Object *ob)
202 {
203         int i;
204         DerivedMesh *dm;
205         MVert *mvert = NULL;
206         
207         dm = mesh_create_derived_render(re->scene, ob,  CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL);
208         mvert= dm->getVertArray(dm);    /* local object space */
209         
210         pd->totpoints= dm->getNumVerts(dm);
211         if (pd->totpoints == 0) return;
212
213         pd->point_tree = BLI_bvhtree_new(pd->totpoints, 0.0, 4, 6);
214         
215         for(i=0; i < pd->totpoints; i++, mvert++) {
216                 float co[3];
217                 
218                 VECCOPY(co, mvert->co);
219
220                 switch(pd->ob_cache_space) {
221                         case TEX_PD_OBJECTSPACE:
222                                 break;
223                         case TEX_PD_OBJECTLOC:
224                                 mul_m4_v3(ob->obmat, co);
225                                 sub_v3_v3(co, ob->loc);
226                                 break;
227                         case TEX_PD_WORLDSPACE:
228                         default:
229                                 mul_m4_v3(ob->obmat, co);
230                                 break;
231                 }
232
233                 BLI_bvhtree_insert(pd->point_tree, i, co, 1);
234         }
235         
236         BLI_bvhtree_balance(pd->point_tree);
237         dm->release(dm);
238
239 }
240 void cache_pointdensity(Render *re, Tex *tex)
241 {
242         PointDensity *pd = tex->pd;
243         
244         if(!pd)
245                 return;
246
247         if (pd->point_tree) {
248                 BLI_bvhtree_free(pd->point_tree);
249                 pd->point_tree = NULL;
250         }
251         
252         if (pd->source == TEX_PD_PSYS) {
253                 Object *ob = pd->object;
254                 ParticleSystem *psys;
255
256                 if (!ob || !pd->psys) return;
257
258                 psys= BLI_findlink(&ob->particlesystem, pd->psys-1);
259                 if (!psys) return;
260                 
261                 pointdensity_cache_psys(re, pd, ob, psys);
262         }
263         else if (pd->source == TEX_PD_OBJECT) {
264                 Object *ob = pd->object;
265                 if (ob && ob->type == OB_MESH)
266                         pointdensity_cache_object(re, pd, ob);
267         }
268 }
269
270 static void free_pointdensity(Render *UNUSED(re), Tex *tex)
271 {
272         PointDensity *pd = tex->pd;
273
274         if (!pd) return;
275         
276         if (pd->point_tree) {
277                 BLI_bvhtree_free(pd->point_tree);
278                 pd->point_tree = NULL;
279         }
280
281         if (pd->point_data) {
282                 MEM_freeN(pd->point_data);
283                 pd->point_data = NULL;
284         }
285         pd->totpoints = 0;
286 }
287
288
289
290 void make_pointdensities(Render *re)
291 {
292         Tex *tex;
293         
294         if(re->scene->r.scemode & R_PREVIEWBUTS)
295                 return;
296         
297         re->i.infostr= "Caching Point Densities";
298         re->stats_draw(re->sdh, &re->i);
299
300         for (tex= re->main->tex.first; tex; tex= tex->id.next) {
301                 if(tex->id.us && tex->type==TEX_POINTDENSITY) {
302                         cache_pointdensity(re, tex);
303                 }
304         }
305         
306         re->i.infostr= NULL;
307         re->stats_draw(re->sdh, &re->i);
308 }
309
310 void free_pointdensities(Render *re)
311 {
312         Tex *tex;
313         
314         if(re->scene->r.scemode & R_PREVIEWBUTS)
315                 return;
316         
317         for (tex= re->main->tex.first; tex; tex= tex->id.next) {
318                 if(tex->id.us && tex->type==TEX_POINTDENSITY) {
319                         free_pointdensity(re, tex);
320                 }
321         }
322 }
323
324 typedef struct PointDensityRangeData
325 {
326         float *density;
327         float squared_radius;
328         float *point_data;
329         float *vec;
330         float softness;
331         short falloff_type;
332         short noise_influence;
333         float *age;
334         int point_data_used;
335         int offset;
336         struct CurveMapping *density_curve;
337         float velscale;
338 } PointDensityRangeData;
339
340 static void accum_density(void *userdata, int index, float squared_dist)
341 {
342         PointDensityRangeData *pdr = (PointDensityRangeData *)userdata;
343         const float dist = (pdr->squared_radius - squared_dist) / pdr->squared_radius * 0.5f;
344         float density = 0.0f;
345         
346         if (pdr->point_data_used & POINT_DATA_VEL) {
347                 pdr->vec[0] += pdr->point_data[index*3 + 0]; //* density;
348                 pdr->vec[1] += pdr->point_data[index*3 + 1]; //* density;
349                 pdr->vec[2] += pdr->point_data[index*3 + 2]; //* density;
350         }
351         if (pdr->point_data_used & POINT_DATA_LIFE) {
352                 *pdr->age += pdr->point_data[pdr->offset + index]; // * density;
353         }
354         
355         if (pdr->falloff_type == TEX_PD_FALLOFF_STD)
356                 density = dist;
357         else if (pdr->falloff_type == TEX_PD_FALLOFF_SMOOTH)
358                 density = 3.0f*dist*dist - 2.0f*dist*dist*dist;
359         else if (pdr->falloff_type == TEX_PD_FALLOFF_SOFT)
360                 density = pow(dist, pdr->softness);
361         else if (pdr->falloff_type == TEX_PD_FALLOFF_CONSTANT)
362                 density = pdr->squared_radius;
363         else if (pdr->falloff_type == TEX_PD_FALLOFF_ROOT)
364                 density = sqrt(dist);
365         else if (pdr->falloff_type == TEX_PD_FALLOFF_PARTICLE_AGE) {
366                 if (pdr->point_data_used & POINT_DATA_LIFE)
367                         density = dist*MIN2(pdr->point_data[pdr->offset + index], 1.0f);
368                 else
369                         density = dist;
370         }
371         else if (pdr->falloff_type == TEX_PD_FALLOFF_PARTICLE_VEL) {
372                 if (pdr->point_data_used & POINT_DATA_VEL)
373                         density = dist*len_v3(pdr->point_data + index*3)*pdr->velscale;
374                 else
375                         density = dist;
376         }
377         
378         if (pdr->density_curve && dist != 0.0f) {
379                 density = curvemapping_evaluateF(pdr->density_curve, 0, density/dist)*dist;
380         }
381         
382         *pdr->density += density;
383 }
384
385
386 static void init_pointdensityrangedata(PointDensity *pd, PointDensityRangeData *pdr, 
387         float *density, float *vec, float *age, struct CurveMapping *density_curve, float velscale)
388 {
389         pdr->squared_radius = pd->radius*pd->radius;
390         pdr->density = density;
391         pdr->point_data = pd->point_data;
392         pdr->falloff_type = pd->falloff_type;
393         pdr->vec = vec;
394         pdr->age = age;
395         pdr->softness = pd->falloff_softness;
396         pdr->noise_influence = pd->noise_influence;
397         pdr->point_data_used = point_data_used(pd);
398         pdr->offset = (pdr->point_data_used & POINT_DATA_VEL)?pd->totpoints*3:0;
399         pdr->density_curve = density_curve;
400         pdr->velscale = velscale;
401 }
402
403
404 int pointdensitytex(Tex *tex, float *texvec, TexResult *texres)
405 {
406         int retval = TEX_INT;
407         PointDensity *pd = tex->pd;
408         PointDensityRangeData pdr;
409         float density=0.0f, age=0.0f, time=0.0f;
410         float vec[3] = {0.0f, 0.0f, 0.0f}, co[3];
411         float col[4];
412         float turb, noise_fac;
413         int num=0;
414         
415         texres->tin = 0.0f;
416         
417         if ((!pd) || (!pd->point_tree))         
418                 return 0;
419                 
420         init_pointdensityrangedata(pd, &pdr, &density, vec, &age, 
421                 (pd->flag&TEX_PD_FALLOFF_CURVE ? pd->falloff_curve : NULL), pd->falloff_speed_scale*0.001f);
422         noise_fac = pd->noise_fac * 0.5f;       /* better default */
423         
424         VECCOPY(co, texvec);
425         
426         if (point_data_used(pd)) {
427                 /* does a BVH lookup to find accumulated density and additional point data *
428                  * stores particle velocity vector in 'vec', and particle lifetime in 'time' */
429                 num = BLI_bvhtree_range_query(pd->point_tree, co, pd->radius, accum_density, &pdr);
430                 if (num > 0) {
431                         age /= num;
432                         mul_v3_fl(vec, 1.0f/num);
433                 }
434                 
435                 /* reset */
436                 density = vec[0] = vec[1] = vec[2] = 0.0f;
437         }
438         
439         if (pd->flag & TEX_PD_TURBULENCE) {
440         
441                 if (pd->noise_influence == TEX_PD_NOISE_AGE) {
442                         turb = BLI_gTurbulence(pd->noise_size, texvec[0]+age, texvec[1]+age, texvec[2]+age, pd->noise_depth, 0, pd->noise_basis);
443                 }
444                 else if (pd->noise_influence == TEX_PD_NOISE_TIME) {
445                         time = R.cfra / (float)R.r.efra;
446                         turb = BLI_gTurbulence(pd->noise_size, texvec[0]+time, texvec[1]+time, texvec[2]+time, pd->noise_depth, 0, pd->noise_basis);
447                         //turb = BLI_turbulence(pd->noise_size, texvec[0]+time, texvec[1]+time, texvec[2]+time, pd->noise_depth);
448                 }
449                 else {
450                         turb = BLI_gTurbulence(pd->noise_size, texvec[0]+vec[0], texvec[1]+vec[1], texvec[2]+vec[2], pd->noise_depth, 0, pd->noise_basis);
451                 }
452
453                 turb -= 0.5f;   /* re-center 0.0-1.0 range around 0 to prevent offsetting result */
454                 
455                 /* now we have an offset coordinate to use for the density lookup */
456                 co[0] = texvec[0] + noise_fac * turb;
457                 co[1] = texvec[1] + noise_fac * turb;
458                 co[2] = texvec[2] + noise_fac * turb;
459         }
460
461         /* BVH query with the potentially perturbed coordinates */
462         num = BLI_bvhtree_range_query(pd->point_tree, co, pd->radius, accum_density, &pdr);
463         if (num > 0) {
464                 age /= num;
465                 mul_v3_fl(vec, 1.0f/num);
466         }
467         
468         texres->tin = density;
469         BRICONT;
470         
471         if (pd->color_source == TEX_PD_COLOR_CONSTANT)
472                 return retval;
473         
474         retval |= TEX_RGB;
475         
476         switch (pd->color_source) {
477                 case TEX_PD_COLOR_PARTAGE:
478                         if (pd->coba) {
479                                 if (do_colorband(pd->coba, age, col)) {
480                                         texres->talpha= 1;
481                                         VECCOPY(&texres->tr, col);
482                                         texres->tin *= col[3];
483                                         texres->ta = texres->tin;
484                                 }
485                         }
486                         break;
487                 case TEX_PD_COLOR_PARTSPEED:
488                 {
489                         float speed = len_v3(vec) * pd->speed_scale;
490                         
491                         if (pd->coba) {
492                                 if (do_colorband(pd->coba, speed, col)) {
493                                         texres->talpha= 1;      
494                                         VECCOPY(&texres->tr, col);
495                                         texres->tin *= col[3];
496                                         texres->ta = texres->tin;
497                                 }
498                         }
499                         break;
500                 }
501                 case TEX_PD_COLOR_PARTVEL:
502                         texres->talpha= 1;
503                         mul_v3_fl(vec, pd->speed_scale);
504                         VECCOPY(&texres->tr, vec);
505                         texres->ta = texres->tin;
506                         break;
507                 case TEX_PD_COLOR_CONSTANT:
508                 default:
509                         texres->tr = texres->tg = texres->tb = texres->ta = 1.0f;
510                         break;
511         }
512         BRICONTRGB;
513         
514         return retval;
515         
516         /*
517         if (texres->nor!=NULL) {
518                 texres->nor[0] = texres->nor[1] = texres->nor[2] = 0.0f;
519         }
520         */
521 }