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