Blender V2.61 - r43446

voxeldata.c

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