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