1a220f6e9b1e2850cc5d724f30e872f64ab5012a
[blender-staging.git] / source / blender / render / intern / source / voxeldata.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): Raul Fernandez Hernandez (Farsthary), Matt Ebb.
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include <math.h>
30 #include <stdlib.h>
31 #include <stdio.h>
32
33 #include "MEM_guardedalloc.h"
34
35 #include "BLI_math.h"
36 #include "BLI_blenlib.h"
37 #include "BLI_voxel.h"
38
39 #include "IMB_imbuf.h"
40 #include "IMB_imbuf_types.h"
41
42 #include "BKE_global.h"
43 #include "BKE_image.h"
44 #include "BKE_main.h"
45 #include "BKE_modifier.h"
46
47 #include "smoke_API.h"
48
49 #include "DNA_texture_types.h"
50 #include "DNA_object_types.h"
51 #include "DNA_modifier_types.h"
52 #include "DNA_smoke_types.h"
53
54
55 #include "render_types.h"
56 #include "renderdatabase.h"
57 #include "texture.h"
58 #include "voxeldata.h"
59
60 void load_frame_blendervoxel(FILE *fp, float *F, int size, int frame, int offset)
61 {       
62         fseek(fp,frame*size*sizeof(float)+offset,0);
63         fread(F,sizeof(float),size,fp);
64 }
65
66 void load_frame_raw8(FILE *fp, float *F, int size, int frame)
67 {
68         char *tmp;
69         int i;
70         
71         tmp = (char *)MEM_mallocN(sizeof(char)*size, "temporary voxel file reading storage");
72         
73         fseek(fp,(frame-1)*size*sizeof(char),0);
74         fread(tmp, sizeof(char), size, fp);
75         
76         for (i=0; i<size; i++) {
77                 F[i] = (float)tmp[i] / 256.f;
78         }
79         MEM_freeN(tmp);
80 }
81
82 void load_frame_image_sequence(Render *re, VoxelData *vd, Tex *tex)
83 {
84         ImBuf *ibuf;
85         Image *ima = tex->ima;
86         ImageUser *iuser = &tex->iuser;
87         int x=0, y=0, z=0;
88         float *rf;
89
90         if (!ima || !iuser) return;
91         
92         ima->source = IMA_SRC_SEQUENCE;
93         iuser->framenr = 1 + iuser->offset;
94
95         /* find the first valid ibuf and use it to initialise the resolution of the data set */
96         /* need to do this in advance so we know how much memory to allocate */
97         ibuf= BKE_image_get_ibuf(ima, iuser);
98         while (!ibuf && (iuser->framenr < iuser->frames)) {
99                 iuser->framenr++;
100                 ibuf= BKE_image_get_ibuf(ima, iuser);
101         }
102         if (!ibuf) return;
103         if (!ibuf->rect_float) IMB_float_from_rect(ibuf);
104         
105         vd->flag |= TEX_VD_STILL;
106         vd->resol[0] = ibuf->x;
107         vd->resol[1] = ibuf->y;
108         vd->resol[2] = iuser->frames;
109         vd->dataset = MEM_mapallocN(sizeof(float)*(vd->resol[0])*(vd->resol[1])*(vd->resol[2]), "voxel dataset");
110         
111         for (z=0; z < iuser->frames; z++)
112         {       
113                 /* get a new ibuf for each frame */
114                 if (z > 0) {
115                         iuser->framenr++;
116                         ibuf= BKE_image_get_ibuf(ima, iuser);
117                         if (!ibuf) break;
118                         if (!ibuf->rect_float) IMB_float_from_rect(ibuf);
119                 }
120                 rf = ibuf->rect_float;
121                 
122                 for (y=0; y < ibuf->y; y++)
123                 {
124                         for (x=0; x < ibuf->x; x++)
125                         {
126                                 /* currently converted to monchrome */
127                                 vd->dataset[ V_I(x, y, z, vd->resol) ] = (rf[0] + rf[1] + rf[2])*0.333f;
128                                 rf +=4;
129                         }
130                 }
131                 
132                 BKE_image_free_anim_ibufs(ima, iuser->framenr);
133         }
134 }
135
136 void write_voxeldata_header(struct VoxelDataHeader *h, FILE *fp)
137 {
138         fwrite(h,sizeof(struct VoxelDataHeader),1,fp);
139 }
140
141 void read_voxeldata_header(FILE *fp, struct VoxelData *vd)
142 {
143         VoxelDataHeader *h=(VoxelDataHeader *)MEM_mallocN(sizeof(VoxelDataHeader), "voxel data header");
144         
145         rewind(fp);
146         fread(h,sizeof(VoxelDataHeader),1,fp);
147         
148         vd->resol[0]=h->resolX;
149         vd->resol[1]=h->resolY;
150         vd->resol[2]=h->resolZ;
151
152         MEM_freeN(h);
153 }
154
155 void init_frame_smoke(Render *re, VoxelData *vd, Tex *tex)
156 {
157         Object *ob;
158         ModifierData *md;
159         
160         vd->dataset = NULL;
161         if (vd->object == NULL) return; 
162         ob= vd->object;
163         
164         /* draw code for smoke */
165         if( (md = (ModifierData *)modifiers_findByType(ob, eModifierType_Smoke)) )
166         {
167                 SmokeModifierData *smd = (SmokeModifierData *)md;
168
169                 
170                 if(smd->domain && smd->domain->fluid) {
171                         
172                         if (vd->smoked_type == TEX_VD_SMOKEHEAT) {
173                                 int totRes;
174                                 float *heat;
175                                 int i;
176
177                                 VECCOPY(vd->resol, smd->domain->res);
178                                 totRes = (vd->resol[0])*(vd->resol[1])*(vd->resol[2]);
179
180                                 // scaling heat values from -2.0-2.0 to 0.0-1.0
181                                 vd->dataset = MEM_mapallocN(sizeof(float)*(totRes), "smoke data");
182
183
184                                 heat = smoke_get_heat(smd->domain->fluid);
185
186                                 for (i=0; i<totRes; i++)
187                                 {
188                                         vd->dataset[i] = (heat[i]+2.0f)/4.0f;
189                                 }
190
191                                 //vd->dataset = smoke_get_heat(smd->domain->fluid);
192                         }
193                         else if (vd->smoked_type == TEX_VD_SMOKEVEL) {
194                                 int totRes;
195                                 float *xvel, *yvel, *zvel;
196                                 int i;
197
198                                 VECCOPY(vd->resol, smd->domain->res);
199                                 totRes = (vd->resol[0])*(vd->resol[1])*(vd->resol[2]);
200
201                                 // scaling heat values from -2.0-2.0 to 0.0-1.0
202                                 vd->dataset = MEM_mapallocN(sizeof(float)*(totRes), "smoke data");
203
204                                 xvel = smoke_get_velocity_x(smd->domain->fluid);
205                                 yvel = smoke_get_velocity_y(smd->domain->fluid);
206                                 zvel = smoke_get_velocity_z(smd->domain->fluid);
207
208                                 for (i=0; i<totRes; i++)
209                                 {
210                                         vd->dataset[i] = sqrt(xvel[i]*xvel[i] + yvel[i]*yvel[i] + zvel[i]*zvel[i])*3.0f;
211                                 }
212
213                         }
214                         else {
215                                 if (smd->domain->flags & MOD_SMOKE_HIGHRES) {
216                                         smoke_turbulence_get_res(smd->domain->wt, vd->resol);
217                                         vd->dataset = smoke_turbulence_get_density(smd->domain->wt);
218                                 } else {
219                                         VECCOPY(vd->resol, smd->domain->res);
220                                         vd->dataset = smoke_get_density(smd->domain->fluid);
221                                 }
222                         } // end of fluid condition
223                 }
224         }
225 }
226
227 void cache_voxeldata(struct Render *re,Tex *tex)
228 {       
229         VoxelData *vd = tex->vd;
230         FILE *fp;
231         int size;
232         int curframe;
233         
234         if (!vd) return;
235         
236         /* image sequence gets special treatment */
237         if (vd->file_format == TEX_VD_IMAGE_SEQUENCE) {
238                 load_frame_image_sequence(re, vd, tex);
239                 return;
240         } else if (vd->file_format == TEX_VD_SMOKE) {
241                 init_frame_smoke(re, vd, tex);
242                 return;
243         }
244
245         if (!BLI_exists(vd->source_path)) return;
246         fp = fopen(vd->source_path,"rb");
247         if (!fp) return;
248
249         if (vd->file_format == TEX_VD_BLENDERVOXEL)
250                 read_voxeldata_header(fp, vd);
251         
252         size = (vd->resol[0])*(vd->resol[1])*(vd->resol[2]);
253         vd->dataset = MEM_mapallocN(sizeof(float)*size, "voxel dataset");
254                 
255         if (vd->flag & TEX_VD_STILL) curframe = vd->still_frame;
256         else curframe = re->r.cfra;
257         
258         switch(vd->file_format) {
259                 case TEX_VD_BLENDERVOXEL:
260                         load_frame_blendervoxel(fp, vd->dataset, size, curframe-1, sizeof(VoxelDataHeader));
261                         break;
262                 case TEX_VD_RAW_8BIT:
263                         load_frame_raw8(fp, vd->dataset, size, curframe);
264                         break;
265         }
266         
267         fclose(fp);
268 }
269
270 void make_voxeldata(struct Render *re)
271 {
272     Tex *tex;
273         
274         re->i.infostr= "Loading voxel datasets";
275         re->stats_draw(re->sdh, &re->i);
276         
277         /* XXX: should be doing only textures used in this render */
278         for (tex= G.main->tex.first; tex; tex= tex->id.next) {
279                 if(tex->id.us && tex->type==TEX_VOXELDATA) {
280                         cache_voxeldata(re, tex);
281                 }
282         }
283         
284         re->i.infostr= NULL;
285         re->stats_draw(re->sdh, &re->i);
286         
287 }
288
289 static void free_voxeldata_one(Render *re, Tex *tex)
290 {
291         VoxelData *vd = tex->vd;
292         
293         if (vd->dataset) {
294                 if(vd->file_format != TEX_VD_SMOKE)
295                         MEM_freeN(vd->dataset);
296                 vd->dataset = NULL;
297         }
298 }
299
300
301 void free_voxeldata(Render *re)
302 {
303         Tex *tex;
304         
305         for (tex= G.main->tex.first; tex; tex= tex->id.next) {
306                 if(tex->id.us && tex->type==TEX_VOXELDATA) {
307                         free_voxeldata_one(re, tex);
308                 }
309         }
310 }
311
312 int voxeldatatex(struct Tex *tex, float *texvec, struct TexResult *texres)
313 {        
314     int retval = TEX_INT;
315         VoxelData *vd = tex->vd;        
316         float co[3], offset[3] = {0.5, 0.5, 0.5};
317
318         if ((!vd) || (vd->dataset==NULL)) {
319                 texres->tin = 0.0f;
320                 return 0;
321         }
322         
323         /* scale lookup from 0.0-1.0 (original location) to -1.0, 1.0, consistent with image texture tex coords */
324         /* in implementation this works backwards, bringing sample locations from -1.0, 1.0
325          * to the range 0.0, 1.0, before looking up in the voxel structure. */
326         copy_v3_v3(co, texvec);
327         mul_v3_fl(co, 0.5f);
328         add_v3_v3v3(co, co, offset);
329
330         /* co is now in the range 0.0, 1.0 */
331         switch (tex->extend) {
332                 case TEX_CLIP:
333                 {
334                         if ((co[0] < 0.f || co[0] > 1.f) || (co[1] < 0.f || co[1] > 1.f) || (co[2] < 0.f || co[2] > 1.f)) {
335                                 texres->tin = 0.f;
336                                 return retval;
337                         }
338                         break;
339                 }
340                 case TEX_REPEAT:
341                 {
342                         co[0] = co[0] - floor(co[0]);
343                         co[1] = co[1] - floor(co[1]);
344                         co[2] = co[2] - floor(co[2]);
345                         break;
346                 }
347                 case TEX_EXTEND:
348                 {
349                         CLAMP(co[0], 0.f, 1.f);
350                         CLAMP(co[1], 0.f, 1.f);
351                         CLAMP(co[2], 0.f, 1.f);
352                         break;
353                 }
354         }
355         
356         switch (vd->interp_type) {
357                 case TEX_VD_NEARESTNEIGHBOR:
358                         texres->tin = voxel_sample_nearest(vd->dataset, vd->resol, co);
359                         break;  
360                 case TEX_VD_LINEAR:
361                         texres->tin = voxel_sample_trilinear(vd->dataset, vd->resol, co);
362                         break;                                  
363                 case TEX_VD_QUADRATIC:
364                         texres->tin = voxel_sample_triquadratic(vd->dataset, vd->resol, co);
365                         break;
366                 case TEX_VD_TRICUBIC_CATROM:
367                 case TEX_VD_TRICUBIC_BSPLINE:
368                         texres->tin = voxel_sample_tricubic(vd->dataset, vd->resol, co, (vd->interp_type == TEX_VD_TRICUBIC_BSPLINE));
369                         break;
370         }
371         
372         texres->tin *= vd->int_multiplier;
373         BRICONT;
374         
375         texres->tr = texres->tin;
376         texres->tg = texres->tin;
377         texres->tb = texres->tin;
378         texres->ta = texres->tin;
379         BRICONTRGB;
380         
381         return retval;  
382 }
383
384