|
Blender
V2.59
|
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