Blender  V2.59
voxeldata.c
Go to the documentation of this file.
00001 /*
00002  *
00003  * ***** BEGIN GPL LICENSE BLOCK *****
00004  *
00005  * This program is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU General Public License
00007  * as published by the Free Software Foundation; either version 2
00008  * of the License, or (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software Foundation,
00017  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00018  *
00019  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00020  * All rights reserved.
00021  *
00022  * The Original Code is: all of this file.
00023  *
00024  * Contributor(s): Raul Fernandez Hernandez (Farsthary), Matt Ebb.
00025  *
00026  * ***** END GPL LICENSE BLOCK *****
00027  */
00028 
00034 #include <math.h>
00035 #include <stdlib.h>
00036 #include <stdio.h>
00037 
00038 #include "MEM_guardedalloc.h"
00039 
00040 #include "BLI_math.h"
00041 #include "BLI_blenlib.h"
00042 #include "BLI_voxel.h"
00043 #include "BLI_utildefines.h"
00044 
00045 #include "IMB_imbuf.h"
00046 #include "IMB_imbuf_types.h"
00047 
00048 #include "BKE_global.h"
00049 #include "BKE_image.h"
00050 #include "BKE_main.h"
00051 #include "BKE_modifier.h"
00052 
00053 #include "smoke_API.h"
00054 
00055 #include "DNA_texture_types.h"
00056 #include "DNA_object_force.h"
00057 #include "DNA_object_types.h"
00058 #include "DNA_modifier_types.h"
00059 #include "DNA_smoke_types.h"
00060 
00061 
00062 #include "render_types.h"
00063 #include "renderdatabase.h"
00064 #include "texture.h"
00065 #include "voxeldata.h"
00066 
00067 static int is_vd_res_ok(VoxelData *vd)
00068 {
00069         /* arbitrary large value so corrupt headers dont break */
00070         const int min= 1, max= 100000;
00071         return  (vd->resol[0] >= min && vd->resol[0] <= max) &&
00072                         (vd->resol[1] >= min && vd->resol[1] <= max) &&
00073                         (vd->resol[2] >= min && vd->resol[2] <= max);
00074 }
00075 
00076 /* use size_t because the result may exceed INT_MAX */
00077 static size_t vd_resol_size(VoxelData *vd)
00078 {
00079         return (size_t)vd->resol[0] * (size_t)vd->resol[1] * (size_t)vd->resol[2];
00080 }
00081 
00082 static int load_frame_blendervoxel(VoxelData *vd, FILE *fp, int frame)
00083 {       
00084         const size_t size = vd_resol_size(vd);
00085         size_t offset = sizeof(VoxelDataHeader);
00086         
00087         if(is_vd_res_ok(vd) == FALSE)
00088                 return 0;
00089 
00090         vd->dataset = MEM_mapallocN(sizeof(float)*size, "voxel dataset");
00091         if(vd->dataset == NULL) return 0;
00092 
00093         if(fseek(fp, frame*size*sizeof(float)+offset, 0) == -1)
00094                 return 0;
00095         if(fread(vd->dataset, sizeof(float), size, fp) != size)
00096                 return 0;
00097         
00098         vd->cachedframe = frame;
00099         vd->ok = 1;
00100         return 1;
00101 }
00102 
00103 static int load_frame_raw8(VoxelData *vd, FILE *fp, int frame)
00104 {
00105         const size_t size = vd_resol_size(vd);
00106         char *data_c;
00107         int i;
00108 
00109         if(is_vd_res_ok(vd) == FALSE)
00110                 return 0;
00111 
00112         vd->dataset = MEM_mapallocN(sizeof(float)*size, "voxel dataset");
00113         if(vd->dataset == NULL) return 0;
00114         data_c = (char *)MEM_mallocN(sizeof(char)*size, "temporary voxel file reading storage");
00115         if(data_c == NULL) {
00116                 MEM_freeN(vd->dataset);
00117                 vd->dataset= NULL;
00118                 return 0;
00119         }
00120 
00121         if(fseek(fp,(frame-1)*size*sizeof(char),0) == -1) {
00122                 MEM_freeN(data_c);
00123                 MEM_freeN(vd->dataset);
00124                 vd->dataset= NULL;
00125                 return 0;
00126         }
00127         if(fread(data_c, sizeof(char), size, fp) != size) {
00128                 MEM_freeN(data_c);
00129                 MEM_freeN(vd->dataset);
00130                 vd->dataset= NULL;
00131                 return 0;
00132         }
00133         
00134         for (i=0; i<size; i++) {
00135                 vd->dataset[i] = (float)data_c[i] / 255.f;
00136         }
00137         MEM_freeN(data_c);
00138         
00139         vd->cachedframe = frame;
00140         vd->ok = 1;
00141         return 1;
00142 }
00143 
00144 static void load_frame_image_sequence(VoxelData *vd, Tex *tex)
00145 {
00146         ImBuf *ibuf;
00147         Image *ima = tex->ima;
00148         ImageUser *tiuser = &tex->iuser;
00149         ImageUser iuser = *(tiuser);
00150         int x=0, y=0, z=0;
00151         float *rf;
00152 
00153         if (!ima || !tiuser) return;
00154         if (iuser.frames == 0) return;
00155         
00156         ima->source = IMA_SRC_SEQUENCE;
00157         iuser.framenr = 1 + iuser.offset;
00158 
00159         /* find the first valid ibuf and use it to initialise the resolution of the data set */
00160         /* need to do this in advance so we know how much memory to allocate */
00161         ibuf= BKE_image_get_ibuf(ima, &iuser);
00162         while (!ibuf && (iuser.framenr < iuser.frames)) {
00163                 iuser.framenr++;
00164                 ibuf= BKE_image_get_ibuf(ima, &iuser);
00165         }
00166         if (!ibuf) return;
00167         if (!ibuf->rect_float) IMB_float_from_rect(ibuf);
00168         
00169         vd->flag |= TEX_VD_STILL;
00170         vd->resol[0] = ibuf->x;
00171         vd->resol[1] = ibuf->y;
00172         vd->resol[2] = iuser.frames;
00173         vd->dataset = MEM_mapallocN(sizeof(float)*vd_resol_size(vd), "voxel dataset");
00174         
00175         for (z=0; z < iuser.frames; z++)
00176         {       
00177                 /* get a new ibuf for each frame */
00178                 if (z > 0) {
00179                         iuser.framenr++;
00180                         ibuf= BKE_image_get_ibuf(ima, &iuser);
00181                         if (!ibuf) break;
00182                         if (!ibuf->rect_float) IMB_float_from_rect(ibuf);
00183                 }
00184                 rf = ibuf->rect_float;
00185                 
00186                 for (y=0; y < ibuf->y; y++)
00187                 {
00188                         for (x=0; x < ibuf->x; x++)
00189                         {
00190                                 /* currently averaged to monchrome */
00191                                 vd->dataset[ V_I(x, y, z, vd->resol) ] = (rf[0] + rf[1] + rf[2])*0.333f;
00192                                 rf +=4;
00193                         }
00194                 }
00195                 
00196                 BKE_image_free_anim_ibufs(ima, iuser.framenr);
00197         }
00198         
00199         vd->ok = 1;
00200         return;
00201 }
00202 
00203 static int read_voxeldata_header(FILE *fp, struct VoxelData *vd)
00204 {
00205         VoxelDataHeader *h=(VoxelDataHeader *)MEM_mallocN(sizeof(VoxelDataHeader), "voxel data header");
00206         
00207         rewind(fp);
00208         if(fread(h,sizeof(VoxelDataHeader),1,fp) != 1) {
00209                 MEM_freeN(h);
00210                 return 0;
00211         }
00212         
00213         vd->resol[0]=h->resolX;
00214         vd->resol[1]=h->resolY;
00215         vd->resol[2]=h->resolZ;
00216 
00217         MEM_freeN(h);
00218         return 1;
00219 }
00220 
00221 static void init_frame_smoke(VoxelData *vd, float cfra)
00222 {
00223 #ifdef WITH_SMOKE
00224         Object *ob;
00225         ModifierData *md;
00226         
00227         vd->dataset = NULL;
00228         if (vd->object == NULL) return; 
00229         ob= vd->object;
00230         
00231         /* draw code for smoke */
00232         if( (md = (ModifierData *)modifiers_findByType(ob, eModifierType_Smoke)) )
00233         {
00234                 SmokeModifierData *smd = (SmokeModifierData *)md;
00235 
00236                 
00237                 if(smd->domain && smd->domain->fluid) {
00238                         if(cfra < smd->domain->point_cache[0]->startframe)
00239                                 ; /* don't show smoke before simulation starts, this could be made an option in the future */
00240                         else if (vd->smoked_type == TEX_VD_SMOKEHEAT) {
00241                                 size_t totRes;
00242                                 size_t i;
00243                                 float *heat;
00244 
00245                                 VECCOPY(vd->resol, smd->domain->res);
00246                                 totRes= vd_resol_size(vd);
00247 
00248                                 // scaling heat values from -2.0-2.0 to 0.0-1.0
00249                                 vd->dataset = MEM_mapallocN(sizeof(float)*(totRes), "smoke data");
00250 
00251 
00252                                 heat = smoke_get_heat(smd->domain->fluid);
00253 
00254                                 for (i=0; i<totRes; i++)
00255                                 {
00256                                         vd->dataset[i] = (heat[i]+2.0f)/4.0f;
00257                                 }
00258 
00259                                 //vd->dataset = smoke_get_heat(smd->domain->fluid);
00260                         }
00261                         else if (vd->smoked_type == TEX_VD_SMOKEVEL) {
00262                                 size_t totRes;
00263                                 size_t i;
00264                                 float *xvel, *yvel, *zvel;
00265 
00266                                 VECCOPY(vd->resol, smd->domain->res);
00267                                 totRes= vd_resol_size(vd);
00268 
00269                                 // scaling heat values from -2.0-2.0 to 0.0-1.0
00270                                 vd->dataset = MEM_mapallocN(sizeof(float)*(totRes), "smoke data");
00271 
00272                                 xvel = smoke_get_velocity_x(smd->domain->fluid);
00273                                 yvel = smoke_get_velocity_y(smd->domain->fluid);
00274                                 zvel = smoke_get_velocity_z(smd->domain->fluid);
00275 
00276                                 for (i=0; i<totRes; i++)
00277                                 {
00278                                         vd->dataset[i] = sqrt(xvel[i]*xvel[i] + yvel[i]*yvel[i] + zvel[i]*zvel[i])*3.0f;
00279                                 }
00280 
00281                         }
00282                         else {
00283                                 size_t totRes;
00284                                 float *density;
00285 
00286                                 if (smd->domain->flags & MOD_SMOKE_HIGHRES) {
00287                                         smoke_turbulence_get_res(smd->domain->wt, vd->resol);
00288                                         density = smoke_turbulence_get_density(smd->domain->wt);
00289                                 } else {
00290                                         VECCOPY(vd->resol, smd->domain->res);
00291                                         density = smoke_get_density(smd->domain->fluid);
00292                                 }
00293 
00294                                 /* TODO: is_vd_res_ok(rvd) doesnt check this resolution */
00295                                 totRes= vd_resol_size(vd);
00296                                 /* always store copy, as smoke internal data can change */
00297                                 vd->dataset = MEM_mapallocN(sizeof(float)*(totRes), "smoke data");
00298                                 memcpy(vd->dataset, density, sizeof(float)*totRes);
00299                         } // end of fluid condition
00300                 }
00301         }
00302         
00303         vd->ok = 1;
00304 
00305 #else // WITH_SMOKE
00306         (void)vd;
00307         (void)cfra;
00308 
00309         vd->dataset= NULL;
00310 #endif
00311 }
00312 
00313 static void cache_voxeldata(struct Render *re, Tex *tex)
00314 {       
00315         VoxelData *vd = tex->vd;
00316         FILE *fp;
00317         int curframe;
00318         char path[sizeof(vd->source_path)];
00319         
00320         /* only re-cache if dataset needs updating */
00321         if ((vd->flag & TEX_VD_STILL) || (vd->cachedframe == re->r.cfra))
00322                 if (vd->ok) return;
00323         
00324         /* clear out old cache, ready for new */
00325         if (vd->dataset) {
00326                 MEM_freeN(vd->dataset);
00327                 vd->dataset = NULL;
00328         }
00329 
00330         if (vd->flag & TEX_VD_STILL)
00331                 curframe = vd->still_frame;
00332         else
00333                 curframe = re->r.cfra;
00334         
00335         BLI_strncpy(path, vd->source_path, sizeof(path));
00336         
00337         switch(vd->file_format) {
00338                 case TEX_VD_IMAGE_SEQUENCE:
00339                         load_frame_image_sequence(vd, tex);
00340                         return;
00341                 case TEX_VD_SMOKE:
00342                         init_frame_smoke(vd, re->r.cfra);
00343                         return;
00344                 case TEX_VD_BLENDERVOXEL:
00345                         BLI_path_abs(path, G.main->name);
00346                         if (!BLI_exists(path)) return;
00347                         fp = fopen(path,"rb");
00348                         if (!fp) return;
00349                         
00350                         if(read_voxeldata_header(fp, vd))
00351                                 load_frame_blendervoxel(vd, fp, curframe-1);
00352 
00353                         fclose(fp);
00354                         return;
00355                 case TEX_VD_RAW_8BIT:
00356                         BLI_path_abs(path, G.main->name);
00357                         if (!BLI_exists(path)) return;
00358                         fp = fopen(path,"rb");
00359                         if (!fp) return;
00360                         
00361                         load_frame_raw8(vd, fp, curframe);
00362                         fclose(fp);
00363                         return;
00364         }
00365 }
00366 
00367 void make_voxeldata(struct Render *re)
00368 {
00369         Tex *tex;
00370         
00371         re->i.infostr= "Loading voxel datasets";
00372         re->stats_draw(re->sdh, &re->i);
00373         
00374         /* XXX: should be doing only textures used in this render */
00375         for (tex= re->main->tex.first; tex; tex= tex->id.next) {
00376                 if(tex->id.us && tex->type==TEX_VOXELDATA) {
00377                         cache_voxeldata(re, tex);
00378                 }
00379         }
00380         
00381         re->i.infostr= NULL;
00382         re->stats_draw(re->sdh, &re->i);
00383         
00384 }
00385 
00386 int voxeldatatex(struct Tex *tex, float *texvec, struct TexResult *texres)
00387 {        
00388         int retval = TEX_INT;
00389         VoxelData *vd = tex->vd;        
00390         float co[3], offset[3] = {0.5, 0.5, 0.5};
00391 
00392         if ((!vd) || (vd->dataset==NULL)) {
00393                 texres->tin = 0.0f;
00394                 return 0;
00395         }
00396         
00397         /* scale lookup from 0.0-1.0 (original location) to -1.0, 1.0, consistent with image texture tex coords */
00398         /* in implementation this works backwards, bringing sample locations from -1.0, 1.0
00399          * to the range 0.0, 1.0, before looking up in the voxel structure. */
00400         copy_v3_v3(co, texvec);
00401         mul_v3_fl(co, 0.5f);
00402         add_v3_v3(co, offset);
00403 
00404         /* co is now in the range 0.0, 1.0 */
00405         switch (vd->extend) {
00406                 case TEX_CLIP:
00407                 {
00408                         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)) {
00409                                 texres->tin = 0.f;
00410                                 return retval;
00411                         }
00412                         break;
00413                 }
00414                 case TEX_REPEAT:
00415                 {
00416                         co[0] = co[0] - floor(co[0]);
00417                         co[1] = co[1] - floor(co[1]);
00418                         co[2] = co[2] - floor(co[2]);
00419                         break;
00420                 }
00421                 case TEX_EXTEND:
00422                 {
00423                         CLAMP(co[0], 0.f, 1.f);
00424                         CLAMP(co[1], 0.f, 1.f);
00425                         CLAMP(co[2], 0.f, 1.f);
00426                         break;
00427                 }
00428         }
00429         
00430         switch (vd->interp_type) {
00431                 case TEX_VD_NEARESTNEIGHBOR:
00432                         texres->tin = voxel_sample_nearest(vd->dataset, vd->resol, co);
00433                         break;  
00434                 case TEX_VD_LINEAR:
00435                         texres->tin = voxel_sample_trilinear(vd->dataset, vd->resol, co);
00436                         break;                                  
00437                 case TEX_VD_QUADRATIC:
00438                         texres->tin = voxel_sample_triquadratic(vd->dataset, vd->resol, co);
00439                         break;
00440                 case TEX_VD_TRICUBIC_CATROM:
00441                 case TEX_VD_TRICUBIC_BSPLINE:
00442                         texres->tin = voxel_sample_tricubic(vd->dataset, vd->resol, co, (vd->interp_type == TEX_VD_TRICUBIC_BSPLINE));
00443                         break;
00444         }
00445         
00446         texres->tin *= vd->int_multiplier;
00447         BRICONT;
00448         
00449         texres->tr = texres->tin;
00450         texres->tg = texres->tin;
00451         texres->tb = texres->tin;
00452         texres->ta = texres->tin;
00453         BRICONTRGB;
00454         
00455         return retval;  
00456 }
00457 
00458