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