Blender V2.61 - r43446
|
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