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