4ec30721274da772a3927041afe4ad6fdd275cf4
[blender.git] / source / blender / render / intern / source / volume_precache.c
1 /**
2  *
3  * ***** BEGIN GPL LICENSE BLOCK *****
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software Foundation,
17  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18  *
19  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
20  * All rights reserved.
21  *
22  * The Original Code is: all of this file.
23  *
24  * Contributor(s): Matt Ebb.
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include <math.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <float.h>
33
34 #include "MEM_guardedalloc.h"
35
36 #include "BLI_blenlib.h"
37 #include "BLI_math.h"
38 #include "BLI_threads.h"
39 #include "BLI_voxel.h"
40
41 #include "PIL_time.h"
42
43 #include "RE_shader_ext.h"
44 #include "RE_raytrace.h"
45
46 #include "DNA_material_types.h"
47
48 #include "render_types.h"
49 #include "rendercore.h"
50 #include "renderdatabase.h"
51 #include "volumetric.h"
52 #include "volume_precache.h"
53
54 #if defined( _MSC_VER ) && !defined( __cplusplus )
55 # define inline __inline
56 #endif // defined( _MSC_VER ) && !defined( __cplusplus )
57
58 #include "BKE_global.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 /* *** utility code to set up an individual raytree for objectinstance, for checking inside/outside *** */
67
68 /* Recursive test for intersections, from a point inside the mesh, to outside
69  * Number of intersections (depth) determine if a point is inside or outside the mesh */
70 int intersect_outside_volume(RayObject *tree, Isect *isect, float *offset, int limit, int depth)
71 {
72         if (limit == 0) return depth;
73         
74         if (RE_rayobject_raycast(tree, isect)) {
75                 
76                 isect->start[0] = isect->start[0] + isect->labda*isect->vec[0];
77                 isect->start[1] = isect->start[1] + isect->labda*isect->vec[1];
78                 isect->start[2] = isect->start[2] + isect->labda*isect->vec[2];
79                 
80                 isect->labda = FLT_MAX;
81                 isect->skip = RE_SKIP_VLR_NEIGHBOUR;
82                 isect->orig.face= isect->hit.face;
83                 isect->orig.ob= isect->hit.ob;
84                 
85                 return intersect_outside_volume(tree, isect, offset, limit-1, depth+1);
86         } else {
87                 return depth;
88         }
89 }
90
91 /* Uses ray tracing to check if a point is inside or outside an ObjectInstanceRen */
92 int point_inside_obi(RayObject *tree, ObjectInstanceRen *obi, float *co)
93 {
94         Isect isect;
95         float vec[3] = {0.0f,0.0f,1.0f};
96         int final_depth=0, depth=0, limit=20;
97         
98         /* set up the isect */
99         memset(&isect, 0, sizeof(isect));
100         VECCOPY(isect.start, co);
101         VECCOPY(isect.vec, vec);
102         isect.mode= RE_RAY_MIRROR;
103         isect.last_hit= NULL;
104         isect.lay= -1;
105         
106         isect.labda = FLT_MAX;
107         isect.orig.face= NULL;
108         isect.orig.ob = NULL;
109
110         final_depth = intersect_outside_volume(tree, &isect, vec, limit, depth);
111         
112         /* even number of intersections: point is outside
113          * odd number: point is inside */
114         if (final_depth % 2 == 0) return 0;
115         else return 1;
116 }
117
118 /* *** light cache filtering *** */
119
120 static float get_avg_surrounds(float *cache, int *res, int xx, int yy, int zz)
121 {
122         int x, y, z, x_, y_, z_;
123         int added=0;
124         float tot=0.0f;
125         
126         for (z=-1; z <= 1; z++) {
127                 z_ = zz+z;
128                 if (z_ >= 0 && z_ <= res[2]-1) {
129                 
130                         for (y=-1; y <= 1; y++) {
131                                 y_ = yy+y;
132                                 if (y_ >= 0 && y_ <= res[1]-1) {
133                                 
134                                         for (x=-1; x <= 1; x++) {
135                                                 x_ = xx+x;
136                                                 if (x_ >= 0 && x_ <= res[0]-1) {
137                                                 
138                                                         if (cache[ V_I(x_, y_, z_, res) ] > 0.0f) {
139                                                                 tot += cache[ V_I(x_, y_, z_, res) ];
140                                                                 added++;
141                                                         }
142                                                         
143                                                 }
144                                         }
145                                 }
146                         }
147                 }
148         }
149         
150         if (added > 0) tot /= added;
151         
152         return tot;
153 }
154
155 /* function to filter the edges of the light cache, where there was no volume originally.
156  * For each voxel which was originally external to the mesh, it finds the average values of
157  * the surrounding internal voxels and sets the original external voxel to that average amount.
158  * Works almost a bit like a 'dilate' filter */
159 static void lightcache_filter(VolumePrecache *vp)
160 {
161         int x, y, z;
162
163         for (z=0; z < vp->res[2]; z++) {
164                 for (y=0; y < vp->res[1]; y++) {
165                         for (x=0; x < vp->res[0]; x++) {
166                                 /* trigger for outside mesh */
167                                 if (vp->data_r[ V_I(x, y, z, vp->res) ] < -0.f)
168                                         vp->data_r[ V_I(x, y, z, vp->res) ] = get_avg_surrounds(vp->data_r, vp->res, x, y, z);
169                                 if (vp->data_g[ V_I(x, y, z, vp->res) ] < -0.f)
170                                         vp->data_g[ V_I(x, y, z, vp->res) ] = get_avg_surrounds(vp->data_g, vp->res, x, y, z);
171                                 if (vp->data_b[ V_I(x, y, z, vp->res) ] < -0.f)
172                                         vp->data_b[ V_I(x, y, z, vp->res) ] = get_avg_surrounds(vp->data_b, vp->res, x, y, z);
173                         }
174                 }
175         }
176 }
177
178 static void lightcache_filter2(VolumePrecache *vp)
179 {
180         int x, y, z;
181         float *new_r, *new_g, *new_b;
182         int field_size = vp->res[0]*vp->res[1]*vp->res[2]*sizeof(float);
183         
184         new_r = MEM_mallocN(field_size, "temp buffer for light cache filter r channel");
185         new_g = MEM_mallocN(field_size, "temp buffer for light cache filter g channel");
186         new_b = MEM_mallocN(field_size, "temp buffer for light cache filter b channel");
187         
188         memcpy(new_r, vp->data_r, field_size);
189         memcpy(new_g, vp->data_g, field_size);
190         memcpy(new_b, vp->data_b, field_size);
191         
192         for (z=0; z < vp->res[2]; z++) {
193                 for (y=0; y < vp->res[1]; y++) {
194                         for (x=0; x < vp->res[0]; x++) {
195                                 /* trigger for outside mesh */
196                                 if (vp->data_r[ V_I(x, y, z, vp->res) ] < -0.f)
197                                         new_r[ V_I(x, y, z, vp->res) ] = get_avg_surrounds(vp->data_r, vp->res, x, y, z);
198                                 if (vp->data_g[ V_I(x, y, z, vp->res) ] < -0.f)
199                                         new_g[ V_I(x, y, z, vp->res) ] = get_avg_surrounds(vp->data_g, vp->res, x, y, z);
200                                 if (vp->data_b[ V_I(x, y, z, vp->res) ] < -0.f)
201                                         new_b[ V_I(x, y, z, vp->res) ] = get_avg_surrounds(vp->data_b, vp->res, x, y, z);
202                         }
203                 }
204         }
205         
206         SWAP(float *, vp->data_r, new_r);
207         SWAP(float *, vp->data_g, new_g);
208         SWAP(float *, vp->data_b, new_b);
209         
210         if (new_r) { MEM_freeN(new_r); new_r=NULL; }
211         if (new_g) { MEM_freeN(new_g); new_g=NULL; }
212         if (new_b) { MEM_freeN(new_b); new_b=NULL; }
213 }
214
215 static inline int ms_I(int x, int y, int z, int *n) //has a pad of 1 voxel surrounding the core for boundary simulation
216
217         return z*(n[1]+2)*(n[0]+2) + y*(n[0]+2) + x;
218 }
219
220
221 /* *** multiple scattering approximation *** */
222
223 /* get the total amount of light energy in the light cache. used to normalise after multiple scattering */
224 static float total_ss_energy(VolumePrecache *vp)
225 {
226         int x, y, z;
227         int *res = vp->res;
228         float energy=0.f;
229         
230         for (z=0; z < res[2]; z++) {
231                 for (y=0; y < res[1]; y++) {
232                         for (x=0; x < res[0]; x++) {
233                                 if (vp->data_r[ V_I(x, y, z, res) ] > 0.f) energy += vp->data_r[ V_I(x, y, z, res) ];
234                                 if (vp->data_g[ V_I(x, y, z, res) ] > 0.f) energy += vp->data_g[ V_I(x, y, z, res) ];
235                                 if (vp->data_b[ V_I(x, y, z, res) ] > 0.f) energy += vp->data_b[ V_I(x, y, z, res) ];
236                         }
237                 }
238         }
239         
240         return energy;
241 }
242
243 static float total_ms_energy(float *sr, float *sg, float *sb, int *res)
244 {
245         int x, y, z, i;
246         float energy=0.f;
247         
248         for (z=1;z<=res[2];z++) {
249                 for (y=1;y<=res[1];y++) {
250                         for (x=1;x<=res[0];x++) {
251                         
252                                 i = ms_I(x,y,z,res);
253                                 if (sr[i] > 0.f) energy += sr[i];
254                                 if (sg[i] > 0.f) energy += sg[i];
255                                 if (sb[i] > 0.f) energy += sb[i];
256                         }
257                 }
258         }
259         
260         return energy;
261 }
262
263 static void ms_diffuse(int b, float* x0, float* x, float diff, int *n)
264 {
265         int i, j, k, l;
266         const float dt = VOL_MS_TIMESTEP;
267         const float a = dt*diff*n[0]*n[1]*n[2];
268         
269         for (l=0; l<20; l++)
270         {
271                 for (k=1; k<=n[2]; k++)
272                 {
273                         for (j=1; j<=n[1]; j++)
274                         {
275                                 for (i=1; i<=n[0]; i++)
276                                 {
277                                         x[ms_I(i,j,k,n)] = (x0[ms_I(i,j,k,n)] + a*(
278                                                  x[ms_I(i-1,j,k,n)]+x[ms_I(i+1,j,k,n)]+
279                                                  x[ms_I(i,j-1,k,n)]+x[ms_I(i,j+1,k,n)]+
280                                                  x[ms_I(i,j,k-1,n)]+x[ms_I(i,j,k+1,n)]))/(1+6*a);
281                                 }
282                         }
283                 }
284         }
285 }
286
287 void multiple_scattering_diffusion(Render *re, VolumePrecache *vp, Material *ma)
288 {
289         const float diff = ma->vol.ms_diff * 0.001f;    /* compensate for scaling for a nicer UI range */
290         const float simframes = ma->vol.ms_steps;
291         const int shade_type = ma->vol.shade_type;
292         float fac = ma->vol.ms_intensity;
293         
294         int x, y, z, m;
295         int *n = vp->res;
296         const int size = (n[0]+2)*(n[1]+2)*(n[2]+2);
297         double time, lasttime= PIL_check_seconds_timer();
298         float total;
299         float c=1.0f;
300         int i;
301         float origf;    /* factor for blending in original light cache */
302         float energy_ss, energy_ms;
303
304         float *sr0=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer");
305         float *sr=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer");
306         float *sg0=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer");
307         float *sg=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer");
308         float *sb0=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer");
309         float *sb=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer");
310
311         total = (float)(n[0]*n[1]*n[2]*simframes);
312         
313         energy_ss = total_ss_energy(vp);
314         
315         /* Scattering as diffusion pass */
316         for (m=0; m<simframes; m++)
317         {
318                 /* add sources */
319                 for (z=1; z<=n[2]; z++)
320                 {
321                         for (y=1; y<=n[1]; y++)
322                         {
323                                 for (x=1; x<=n[0]; x++)
324                                 {
325                                         i = V_I((x-1), (y-1), (z-1), n);
326                                         time= PIL_check_seconds_timer();
327                                         c++;
328                                                                                 
329                                         if (vp->data_r[i] > 0.f)
330                                                 sr[ms_I(x,y,z,n)] += vp->data_r[i];
331                                         if (vp->data_g[i] > 0.f)
332                                                 sg[ms_I(x,y,z,n)] += vp->data_g[i];
333                                         if (vp->data_b[i] > 0.f)
334                                                 sb[ms_I(x,y,z,n)] += vp->data_b[i];
335                                         
336                                         /* Displays progress every second */
337                                         if(time-lasttime>1.0f) {
338                                                 char str[64];
339                                                 sprintf(str, "Simulating multiple scattering: %d%%", (int)
340                                                                 (100.0f * (c / total)));
341                                                 re->i.infostr= str;
342                                                 re->stats_draw(re->sdh, &re->i);
343                                                 re->i.infostr= NULL;
344                                                 lasttime= time;
345                                         }
346                                 }
347                         }
348                 }
349                 SWAP(float *, sr, sr0);
350                 SWAP(float *, sg, sg0);
351                 SWAP(float *, sb, sb0);
352
353                 /* main diffusion simulation */
354                 ms_diffuse(0, sr0, sr, diff, n);
355                 ms_diffuse(0, sg0, sg, diff, n);
356                 ms_diffuse(0, sb0, sb, diff, n);
357                 
358                 if (re->test_break(re->tbh)) break;
359         }
360         
361         /* normalisation factor to conserve energy */
362         energy_ms = total_ms_energy(sr, sg, sb, n);
363         fac *= (energy_ss / energy_ms);
364         
365         /* blend multiple scattering back in the light cache */
366         if (shade_type == MA_VOL_SHADE_SHADEDPLUSMULTIPLE) {
367                 /* conserve energy - half single, half multiple */
368                 origf = 0.5f;
369                 fac *= 0.5f;
370         } else {
371                 origf = 0.0f;
372         }
373
374         for (z=1;z<=n[2];z++)
375         {
376                 for (y=1;y<=n[1];y++)
377                 {
378                         for (x=1;x<=n[0];x++)
379                         {
380                                 int index=(x-1)*n[1]*n[2] + (y-1)*n[2] + z-1;
381                                 vp->data_r[index] = origf * vp->data_r[index] + fac * sr[ms_I(x,y,z,n)];
382                                 vp->data_g[index] = origf * vp->data_g[index] + fac * sg[ms_I(x,y,z,n)];
383                                 vp->data_b[index] = origf * vp->data_b[index] + fac * sb[ms_I(x,y,z,n)];
384                         }
385                 }
386         }
387
388         MEM_freeN(sr0);
389         MEM_freeN(sr);
390         MEM_freeN(sg0);
391         MEM_freeN(sg);
392         MEM_freeN(sb0);
393         MEM_freeN(sb);
394 }
395
396
397
398 #if 0 // debug stuff
399 static void *vol_precache_part_test(void *data)
400 {
401         VolPrecachePart *pa = data;
402
403         printf("part number: %d \n", pa->num);
404         printf("done: %d \n", pa->done);
405         printf("x min: %d   x max: %d \n", pa->minx, pa->maxx);
406         printf("y min: %d   y max: %d \n", pa->miny, pa->maxy);
407         printf("z min: %d   z max: %d \n", pa->minz, pa->maxz);
408
409         return NULL;
410 }
411 #endif
412
413 /* Iterate over the 3d voxel grid, and fill the voxels with scattering information
414  *
415  * It's stored in memory as 3 big float grids next to each other, one for each RGB channel.
416  * I'm guessing the memory alignment may work out better this way for the purposes
417  * of doing linear interpolation, but I haven't actually tested this theory! :)
418  */
419 static void *vol_precache_part(void *data)
420 {
421         VolPrecachePart *pa =  (VolPrecachePart *)data;
422         ObjectInstanceRen *obi = pa->obi;
423         RayObject *tree = pa->tree;
424         ShadeInput *shi = pa->shi;
425         float scatter_col[3] = {0.f, 0.f, 0.f};
426         float co[3];
427         int x, y, z;
428         const int res[3]= {pa->res[0], pa->res[1], pa->res[2]};
429
430         for (z= pa->minz; z < pa->maxz; z++) {
431                 co[2] = pa->bbmin[2] + (pa->voxel[2] * (z + 0.5f));
432                 
433                 for (y= pa->miny; y < pa->maxy; y++) {
434                         co[1] = pa->bbmin[1] + (pa->voxel[1] * (y + 0.5f));
435                         
436                         for (x=pa->minx; x < pa->maxx; x++) {
437                                 co[0] = pa->bbmin[0] + (pa->voxel[0] * (x + 0.5f));
438                                 
439                                 // don't bother if the point is not inside the volume mesh
440                                 if (!point_inside_obi(tree, obi, co)) {
441                                         obi->volume_precache->data_r[ V_I(x, y, z, res) ] = -1.0f;
442                                         obi->volume_precache->data_g[ V_I(x, y, z, res) ] = -1.0f;
443                                         obi->volume_precache->data_b[ V_I(x, y, z, res) ] = -1.0f;
444                                         continue;
445                                 }
446                                 
447                                 copy_v3_v3(shi->view, co);
448                                 normalize_v3(shi->view);
449                                 vol_get_scattering(shi, scatter_col, co);
450                         
451                                 obi->volume_precache->data_r[ V_I(x, y, z, res) ] = scatter_col[0];
452                                 obi->volume_precache->data_g[ V_I(x, y, z, res) ] = scatter_col[1];
453                                 obi->volume_precache->data_b[ V_I(x, y, z, res) ] = scatter_col[2];
454                         }
455                 }
456         }
457         
458         pa->done = 1;
459         
460         return 0;
461 }
462
463
464 static void precache_setup_shadeinput(Render *re, ObjectInstanceRen *obi, Material *ma, ShadeInput *shi)
465 {
466         memset(shi, 0, sizeof(ShadeInput)); 
467         shi->depth= 1;
468         shi->mask= 1;
469         shi->mat = ma;
470         shi->vlr = NULL;
471         memcpy(&shi->r, &shi->mat->r, 23*sizeof(float));        // note, keep this synced with render_types.h
472         shi->har= shi->mat->har;
473         shi->obi= obi;
474         shi->obr= obi->obr;
475         shi->lay = re->scene->lay;
476 }
477
478 static void precache_init_parts(Render *re, RayObject *tree, ShadeInput *shi, ObjectInstanceRen *obi, int totthread, int *parts)
479 {
480         VolumePrecache *vp = obi->volume_precache;
481         int i=0, x, y, z;
482         float voxel[3];
483         int sizex, sizey, sizez;
484         float *bbmin=obi->obr->boundbox[0], *bbmax=obi->obr->boundbox[1];
485         int *res;
486         int minx, maxx;
487         int miny, maxy;
488         int minz, maxz;
489         
490         if (!vp) return;
491
492         BLI_freelistN(&re->volume_precache_parts);
493         
494         /* currently we just subdivide the box, number of threads per side */
495         parts[0] = parts[1] = parts[2] = totthread;
496         res = vp->res;
497         
498         sub_v3_v3v3(voxel, bbmax, bbmin);
499         
500         voxel[0] /= res[0];
501         voxel[1] /= res[1];
502         voxel[2] /= res[2];
503
504         for (x=0; x < parts[0]; x++) {
505                 sizex = ceil(res[0] / (float)parts[0]);
506                 minx = x * sizex;
507                 maxx = minx + sizex;
508                 maxx = (maxx>res[0])?res[0]:maxx;
509                 
510                 for (y=0; y < parts[1]; y++) {
511                         sizey = ceil(res[1] / (float)parts[1]);
512                         miny = y * sizey;
513                         maxy = miny + sizey;
514                         maxy = (maxy>res[1])?res[1]:maxy;
515                         
516                         for (z=0; z < parts[2]; z++) {
517                                 VolPrecachePart *pa= MEM_callocN(sizeof(VolPrecachePart), "new precache part");
518                                 
519                                 sizez = ceil(res[2] / (float)parts[2]);
520                                 minz = z * sizez;
521                                 maxz = minz + sizez;
522                                 maxz = (maxz>res[2])?res[2]:maxz;
523                                                 
524                                 pa->done = 0;
525                                 pa->working = 0;
526                                 
527                                 pa->num = i;
528                                 pa->tree = tree;
529                                 pa->shi = shi;
530                                 pa->obi = obi;
531                                 VECCOPY(pa->bbmin, bbmin);
532                                 VECCOPY(pa->voxel, voxel);
533                                 VECCOPY(pa->res, res);
534                                 
535                                 pa->minx = minx; pa->maxx = maxx;
536                                 pa->miny = miny; pa->maxy = maxy;
537                                 pa->minz = minz; pa->maxz = maxz;
538                                 
539                                 
540                                 BLI_addtail(&re->volume_precache_parts, pa);
541                                 
542                                 i++;
543                         }
544                 }
545         }
546 }
547
548 static VolPrecachePart *precache_get_new_part(Render *re)
549 {
550         VolPrecachePart *pa, *nextpa=NULL;
551         
552         for (pa = re->volume_precache_parts.first; pa; pa=pa->next)
553         {
554                 if (pa->done==0 && pa->working==0) {
555                         nextpa = pa;
556                         break;
557                 }
558         }
559
560         return nextpa;
561 }
562
563 static int precache_resolution(VolumePrecache *vp, float *bbmin, float *bbmax, int res)
564 {
565         float dim[3], div;
566         
567         sub_v3_v3v3(dim, bbmax, bbmin);
568         
569         div = MAX3(dim[0], dim[1], dim[2]);
570         dim[0] /= div;
571         dim[1] /= div;
572         dim[2] /= div;
573         
574         vp->res[0] = dim[0] * (float)res;
575         vp->res[1] = dim[1] * (float)res;
576         vp->res[2] = dim[2] * (float)res;
577         
578         if ((vp->res[0] < 1) || (vp->res[1] < 1) || (vp->res[2] < 1))
579                 return 0;
580         
581         return 1;
582 }
583
584 /* Precache a volume into a 3D voxel grid.
585  * The voxel grid is stored in the ObjectInstanceRen, 
586  * in camera space, aligned with the ObjectRen's bounding box.
587  * Resolution is defined by the user.
588  */
589 void vol_precache_objectinstance_threads(Render *re, ObjectInstanceRen *obi, Material *ma)
590 {
591         VolumePrecache *vp;
592         VolPrecachePart *nextpa, *pa;
593         RayObject *tree;
594         ShadeInput shi;
595         ListBase threads;
596         float *bbmin=obi->obr->boundbox[0], *bbmax=obi->obr->boundbox[1];
597         int parts[3] = {1, 1, 1}, totparts;
598         
599         int caching=1, counter=0;
600         int totthread = re->r.threads;
601         
602         double time, lasttime= PIL_check_seconds_timer();
603         
604         R = *re;
605
606         /* create a raytree with just the faces of the instanced ObjectRen, 
607          * used for checking if the cached point is inside or outside. */
608         //tree = create_raytree_obi(obi, bbmin, bbmax);
609         tree = makeraytree_object(&R, obi);
610         if (!tree) return;
611         INIT_MINMAX(bbmin, bbmax);
612         RE_rayobject_merge_bb( tree, bbmin, bbmax);
613
614         vp = MEM_callocN(sizeof(VolumePrecache), "volume light cache");
615         
616         if (!precache_resolution(vp, bbmin, bbmax, ma->vol.precache_resolution)) {
617                 MEM_freeN(vp);
618                 vp = NULL;
619                 return;
620         }
621
622         vp->data_r = MEM_callocN(sizeof(float)*vp->res[0]*vp->res[1]*vp->res[2], "volume light cache data red channel");
623         vp->data_g = MEM_callocN(sizeof(float)*vp->res[0]*vp->res[1]*vp->res[2], "volume light cache data green channel");
624         vp->data_b = MEM_callocN(sizeof(float)*vp->res[0]*vp->res[1]*vp->res[2], "volume light cache data blue channel");
625         if (vp->data_r==0 || vp->data_g==0 || vp->data_b==0) {
626                 MEM_freeN(vp);
627                 vp = NULL;
628                 return;
629         }
630         obi->volume_precache = vp;
631
632         /* Need a shadeinput to calculate scattering */
633         precache_setup_shadeinput(re, obi, ma, &shi);
634         
635         precache_init_parts(re, tree, &shi, obi, totthread, parts);
636         totparts = parts[0] * parts[1] * parts[2];
637         
638         BLI_init_threads(&threads, vol_precache_part, totthread);
639         
640         while(caching) {
641
642                 if(BLI_available_threads(&threads) && !(re->test_break(re->tbh))) {
643                         nextpa = precache_get_new_part(re);
644                         if (nextpa) {
645                                 nextpa->working = 1;
646                                 BLI_insert_thread(&threads, nextpa);
647                         }
648                 }
649                 else PIL_sleep_ms(50);
650
651                 caching=0;
652                 counter=0;
653                 for(pa= re->volume_precache_parts.first; pa; pa= pa->next) {
654                         
655                         if(pa->done) {
656                                 counter++;
657                                 BLI_remove_thread(&threads, pa);
658                         } else
659                                 caching = 1;
660                 }
661                 
662                 if (re->test_break(re->tbh) && BLI_available_threads(&threads)==totthread)
663                         caching=0;
664                 
665                 time= PIL_check_seconds_timer();
666                 if(time-lasttime>1.0f) {
667                         char str[64];
668                         sprintf(str, "Precaching volume: %d%%", (int)(100.0f * ((float)counter / (float)totparts)));
669                         re->i.infostr= str;
670                         re->stats_draw(re->sdh, &re->i);
671                         re->i.infostr= NULL;
672                         lasttime= time;
673                 }
674         }
675         
676         BLI_end_threads(&threads);
677         BLI_freelistN(&re->volume_precache_parts);
678         
679         if(tree) {
680                 //TODO: makeraytree_object creates a tree and saves it on OBI, if we free this tree we should also clear other pointers to it
681                 //RE_rayobject_free(tree);
682                 //tree= NULL;
683         }
684         
685         lightcache_filter(obi->volume_precache);
686         
687         if (ELEM(ma->vol.shade_type, MA_VOL_SHADE_MULTIPLE, MA_VOL_SHADE_SHADEDPLUSMULTIPLE))
688         {
689                 multiple_scattering_diffusion(re, vp, ma);
690         }
691 }
692
693 static int using_lightcache(Material *ma)
694 {
695         return (((ma->vol.shadeflag & MA_VOL_PRECACHESHADING) && (ma->vol.shade_type == MA_VOL_SHADE_SHADED))
696                 || (ELEM(ma->vol.shade_type, MA_VOL_SHADE_MULTIPLE, MA_VOL_SHADE_SHADEDPLUSMULTIPLE)));
697 }
698
699 /* loop through all objects (and their associated materials)
700  * marked for pre-caching in convertblender.c, and pre-cache them */
701 void volume_precache(Render *re)
702 {
703         ObjectInstanceRen *obi;
704         VolumeOb *vo;
705
706         for(vo= re->volumes.first; vo; vo= vo->next) {
707                 if (using_lightcache(vo->ma)) {
708                         for(obi= re->instancetable.first; obi; obi= obi->next) {
709                                 if (obi->obr == vo->obr) {
710                                         vol_precache_objectinstance_threads(re, obi, vo->ma);
711                                 }
712                         }
713                 }
714         }
715         
716         re->i.infostr= NULL;
717         re->stats_draw(re->sdh, &re->i);
718 }
719
720 void free_volume_precache(Render *re)
721 {
722         ObjectInstanceRen *obi;
723         
724         for(obi= re->instancetable.first; obi; obi= obi->next) {
725                 if (obi->volume_precache != NULL) {
726                         MEM_freeN(obi->volume_precache->data_r);
727                         MEM_freeN(obi->volume_precache->data_g);
728                         MEM_freeN(obi->volume_precache->data_b);
729                         MEM_freeN(obi->volume_precache);
730                         obi->volume_precache = NULL;
731                 }
732         }
733         
734         BLI_freelistN(&re->volumes);
735 }
736
737 int point_inside_volume_objectinstance(Render *re, ObjectInstanceRen *obi, float *co)
738 {
739         RayObject *tree;
740         int inside=0;
741         
742         tree = makeraytree_object(re, obi); //create_raytree_obi(obi, obi->obr->boundbox[0], obi->obr->boundbox[1]);
743         if (!tree) return 0;
744         
745         inside = point_inside_obi(tree, obi, co);
746         
747         //TODO: makeraytree_object creates a tree and saves it on OBI, if we free this tree we should also clear other pointers to it
748         //RE_rayobject_free(tree);
749         //tree= NULL;
750         
751         return inside;
752 }
753