diff options
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/blenkernel/BKE_pointcache.h | 15 | ||||
-rw-r--r-- | source/blender/blenkernel/CMakeLists.txt | 13 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/pointcache.c | 481 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/smoke.c | 11 | ||||
-rw-r--r-- | source/blender/editors/space_view3d/drawobject.c | 18 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_smoke_types.h | 14 | ||||
-rw-r--r-- | source/blender/makesrna/intern/CMakeLists.txt | 8 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_smoke.c | 43 | ||||
-rw-r--r-- | source/blender/python/intern/CMakeLists.txt | 9 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_app.c | 3 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_app_build_options.c | 7 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_app_openvdb.c | 117 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_app_openvdb.h | 38 | ||||
-rw-r--r-- | source/blenderplayer/CMakeLists.txt | 4 |
14 files changed, 736 insertions, 45 deletions
diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h index d1b8aa672c5..40dbffe7222 100644 --- a/source/blender/blenkernel/BKE_pointcache.h +++ b/source/blender/blenkernel/BKE_pointcache.h @@ -94,6 +94,9 @@ struct SmokeModifierData; struct SoftBody; struct RigidBodyWorld; +struct OpenVDBReader; +struct OpenVDBWriter; + /* temp structure for read/write */ typedef struct PTCacheData { unsigned int index; @@ -119,13 +122,18 @@ typedef struct PTCacheFile { #define PTCACHE_VEL_PER_SEC 1 +enum { + PTCACHE_FILE_PTCACHE = 0, + PTCACHE_FILE_OPENVDB = 1, +}; + typedef struct PTCacheID { struct PTCacheID *next, *prev; struct Scene *scene; struct Object *ob; void *calldata; - unsigned int type; + unsigned int type, file_type; unsigned int stack_index; unsigned int flag; @@ -147,6 +155,11 @@ typedef struct PTCacheID { /* copies cache cata to point data */ int (*read_stream)(PTCacheFile *pf, void *calldata); + /* copies point data to cache data */ + int (*write_openvdb_stream)(struct OpenVDBWriter *writer, void *calldata); + /* copies cache cata to point data */ + int (*read_openvdb_stream)(struct OpenVDBReader *reader, void *calldata); + /* copies custom extradata to cache data */ void (*write_extra_data)(void *calldata, struct PTCacheMem *pm, int cfra); /* copies custom extradata to cache data */ diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 3ba6eb6c66d..b0a105bb910 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -517,6 +517,19 @@ if(WITH_OPENSUBDIV) endif() endif() +if(WITH_OPENVDB) + add_definitions(-DWITH_OPENVDB) + list(APPEND INC + ../../../intern/openvdb + ) + + if(WITH_OPENVDB_BLOSC) + add_definitions( + -DWITH_OPENVDB_BLOSC + ) + endif() +endif() + ## Warnings as errors, this is too strict! #if(MSVC) # set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX") diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index ad599942b50..8d6edcec0c7 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -83,6 +83,10 @@ #include "smoke_API.h" #endif +#ifdef WITH_OPENVDB +#include "openvdb_capi.h" +#endif + #ifdef WITH_LZO # ifdef WITH_SYSTEM_LZO # include <lzo/lzo1x.h> @@ -887,6 +891,274 @@ static int ptcache_smoke_read(PTCacheFile *pf, void *smoke_v) return 1; } +#ifdef WITH_OPENVDB +/** + * Construct matrices which represent the fluid object, for low and high res: + * <pre> + * vs 0 0 0 + * 0 vs 0 0 + * 0 0 vs 0 + * px py pz 1 + * </pre> + * + * with `vs` = voxel size, and `px, py, pz`, + * the min position of the domain's bounding box. + */ +static void compute_fluid_matrices(SmokeDomainSettings *sds) +{ + float bbox_min[3]; + + copy_v3_v3(bbox_min, sds->p0); + + if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) { + bbox_min[0] += (sds->cell_size[0] * (float)sds->res_min[0]); + bbox_min[1] += (sds->cell_size[1] * (float)sds->res_min[1]); + bbox_min[2] += (sds->cell_size[2] * (float)sds->res_min[2]); + add_v3_v3(bbox_min, sds->obj_shift_f); + } + + /* construct low res matrix */ + size_to_mat4(sds->fluidmat, sds->cell_size); + copy_v3_v3(sds->fluidmat[3], bbox_min); + + /* The smoke simulator stores voxels cell-centered, whilst VDB is node + * centered, so we offset the matrix by half a voxel to compensate. */ + madd_v3_v3fl(sds->fluidmat[3], sds->cell_size, 0.5f); + + mul_m4_m4m4(sds->fluidmat, sds->obmat, sds->fluidmat); + + if (sds->wt) { + float voxel_size_high[3]; + /* construct high res matrix */ + mul_v3_v3fl(voxel_size_high, sds->cell_size, 1.0f / (float)(sds->amplify + 1)); + size_to_mat4(sds->fluidmat_wt, voxel_size_high); + copy_v3_v3(sds->fluidmat_wt[3], bbox_min); + + /* Same here, add half a voxel to adjust the position of the fluid. */ + madd_v3_v3fl(sds->fluidmat_wt[3], voxel_size_high, 0.5f); + + mul_m4_m4m4(sds->fluidmat_wt, sds->obmat, sds->fluidmat_wt); + } +} + +static int ptcache_smoke_openvdb_write(struct OpenVDBWriter *writer, void *smoke_v) +{ + SmokeModifierData *smd = (SmokeModifierData *)smoke_v; + SmokeDomainSettings *sds = smd->domain; + + OpenVDBWriter_set_flags(writer, sds->openvdb_comp, (sds->data_depth == 16)); + + OpenVDBWriter_add_meta_int(writer, "blender/smoke/active_fields", sds->active_fields); + OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/resolution", sds->res); + OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/min_resolution", sds->res_min); + OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/max_resolution", sds->res_max); + OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/base_resolution", sds->base_res); + OpenVDBWriter_add_meta_v3(writer, "blender/smoke/min_bbox", sds->p0); + OpenVDBWriter_add_meta_v3(writer, "blender/smoke/max_bbox", sds->p1); + OpenVDBWriter_add_meta_v3(writer, "blender/smoke/dp0", sds->dp0); + OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/shift", sds->shift); + OpenVDBWriter_add_meta_v3(writer, "blender/smoke/obj_shift_f", sds->obj_shift_f); + OpenVDBWriter_add_meta_v3(writer, "blender/smoke/active_color", sds->active_color); + OpenVDBWriter_add_meta_mat4(writer, "blender/smoke/obmat", sds->obmat); + + int fluid_fields = smoke_get_data_flags(sds); + + struct OpenVDBFloatGrid *clip_grid = NULL; + + compute_fluid_matrices(sds); + + OpenVDBWriter_add_meta_int(writer, "blender/smoke/fluid_fields", fluid_fields); + + if (sds->wt) { + struct OpenVDBFloatGrid *wt_density_grid; + float *dens, *react, *fuel, *flame, *tcu, *tcv, *tcw, *r, *g, *b; + + smoke_turbulence_export(sds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw); + + wt_density_grid = OpenVDB_export_grid_fl(writer, "density", dens, sds->res_wt, sds->fluidmat_wt, NULL); + clip_grid = wt_density_grid; + + if (fluid_fields & SM_ACTIVE_FIRE) { + OpenVDB_export_grid_fl(writer, "flame", flame, sds->res_wt, sds->fluidmat_wt, wt_density_grid); + OpenVDB_export_grid_fl(writer, "fuel", fuel, sds->res_wt, sds->fluidmat_wt, wt_density_grid); + OpenVDB_export_grid_fl(writer, "react", react, sds->res_wt, sds->fluidmat_wt, wt_density_grid); + } + + if (fluid_fields & SM_ACTIVE_COLORS) { + OpenVDB_export_grid_vec(writer, "color", r, g, b, sds->res_wt, sds->fluidmat_wt, VEC_INVARIANT, true, wt_density_grid); + } + + OpenVDB_export_grid_vec(writer, "texture coordinates", tcu, tcv, tcw, sds->res, sds->fluidmat, VEC_INVARIANT, false, wt_density_grid); + } + + if (sds->fluid) { + struct OpenVDBFloatGrid *density_grid; + float dt, dx, *dens, *react, *fuel, *flame, *heat, *heatold, *vx, *vy, *vz, *r, *g, *b; + unsigned char *obstacles; + + smoke_export(sds->fluid, &dt, &dx, &dens, &react, &flame, &fuel, &heat, + &heatold, &vx, &vy, &vz, &r, &g, &b, &obstacles); + + OpenVDBWriter_add_meta_fl(writer, "blender/smoke/dx", dx); + OpenVDBWriter_add_meta_fl(writer, "blender/smoke/dt", dt); + + const char *name = (!sds->wt) ? "density" : "density low"; + density_grid = OpenVDB_export_grid_fl(writer, name, dens, sds->res, sds->fluidmat, NULL); + clip_grid = sds->wt ? clip_grid : density_grid; + + OpenVDB_export_grid_fl(writer, "shadow", sds->shadow, sds->res, sds->fluidmat, NULL); + + if (fluid_fields & SM_ACTIVE_HEAT) { + OpenVDB_export_grid_fl(writer, "heat", heat, sds->res, sds->fluidmat, clip_grid); + OpenVDB_export_grid_fl(writer, "heat old", heatold, sds->res, sds->fluidmat, clip_grid); + } + + if (fluid_fields & SM_ACTIVE_FIRE) { + name = (!sds->wt) ? "flame" : "flame low"; + OpenVDB_export_grid_fl(writer, name, flame, sds->res, sds->fluidmat, density_grid); + name = (!sds->wt) ? "fuel" : "fuel low"; + OpenVDB_export_grid_fl(writer, name, fuel, sds->res, sds->fluidmat, density_grid); + name = (!sds->wt) ? "react" : "react low"; + OpenVDB_export_grid_fl(writer, name, react, sds->res, sds->fluidmat, density_grid); + } + + if (fluid_fields & SM_ACTIVE_COLORS) { + name = (!sds->wt) ? "color" : "color low"; + OpenVDB_export_grid_vec(writer, name, r, g, b, sds->res, sds->fluidmat, VEC_INVARIANT, true, density_grid); + } + + OpenVDB_export_grid_vec(writer, "velocity", vx, vy, vz, sds->res, sds->fluidmat, VEC_CONTRAVARIANT_RELATIVE, false, clip_grid); + OpenVDB_export_grid_ch(writer, "obstacles", obstacles, sds->res, sds->fluidmat, NULL); + } + + return 1; +} + +static int ptcache_smoke_openvdb_read(struct OpenVDBReader *reader, void *smoke_v) +{ + SmokeModifierData *smd = (SmokeModifierData *)smoke_v; + + if (!smd) { + return 0; + } + + SmokeDomainSettings *sds = smd->domain; + + int fluid_fields = smoke_get_data_flags(sds); + int active_fields, cache_fields = 0; + int cache_res[3]; + float cache_dx; + bool reallocate = false; + + OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/min_resolution", sds->res_min); + OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/max_resolution", sds->res_max); + OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/base_resolution", sds->base_res); + OpenVDBReader_get_meta_v3(reader, "blender/smoke/min_bbox", sds->p0); + OpenVDBReader_get_meta_v3(reader, "blender/smoke/max_bbox", sds->p1); + OpenVDBReader_get_meta_v3(reader, "blender/smoke/dp0", sds->dp0); + OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/shift", sds->shift); + OpenVDBReader_get_meta_v3(reader, "blender/smoke/obj_shift_f", sds->obj_shift_f); + OpenVDBReader_get_meta_v3(reader, "blender/smoke/active_color", sds->active_color); + OpenVDBReader_get_meta_mat4(reader, "blender/smoke/obmat", sds->obmat); + OpenVDBReader_get_meta_int(reader, "blender/smoke/fluid_fields", &cache_fields); + OpenVDBReader_get_meta_int(reader, "blender/smoke/active_fields", &active_fields); + OpenVDBReader_get_meta_fl(reader, "blender/smoke/dx", &cache_dx); + OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/resolution", cache_res); + + /* check if resolution has changed */ + if (sds->res[0] != cache_res[0] || + sds->res[1] != cache_res[1] || + sds->res[2] != cache_res[2]) + { + if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) { + reallocate = true; + } + else { + return 0; + } + } + + /* check if active fields have changed */ + if ((fluid_fields != cache_fields) || (active_fields != sds->active_fields)) { + reallocate = true; + } + + /* reallocate fluid if needed*/ + if (reallocate) { + sds->active_fields = active_fields | cache_fields; + smoke_reallocate_fluid(sds, cache_dx, cache_res, 1); + sds->dx = cache_dx; + copy_v3_v3_int(sds->res, cache_res); + sds->total_cells = cache_res[0] * cache_res[1] * cache_res[2]; + + if (sds->flags & MOD_SMOKE_HIGHRES) { + smoke_reallocate_highres_fluid(sds, cache_dx, cache_res, 1); + } + } + + if (sds->fluid) { + float dt, dx, *dens, *react, *fuel, *flame, *heat, *heatold, *vx, *vy, *vz, *r, *g, *b; + unsigned char *obstacles; + + smoke_export(sds->fluid, &dt, &dx, &dens, &react, &flame, &fuel, &heat, + &heatold, &vx, &vy, &vz, &r, &g, &b, &obstacles); + + OpenVDBReader_get_meta_fl(reader, "blender/smoke/dt", &dt); + + OpenVDB_import_grid_fl(reader, "shadow", &sds->shadow, sds->res); + + const char *name = (!sds->wt) ? "density" : "density Low"; + OpenVDB_import_grid_fl(reader, name, &dens, sds->res); + + if (fluid_fields & SM_ACTIVE_HEAT) { + OpenVDB_import_grid_fl(reader, "heat", &heat, sds->res); + OpenVDB_import_grid_fl(reader, "heat old", &heatold, sds->res); + } + + if (fluid_fields & SM_ACTIVE_FIRE) { + name = (!sds->wt) ? "flame" : "flame low"; + OpenVDB_import_grid_fl(reader, name, &flame, sds->res); + name = (!sds->wt) ? "fuel" : "fuel low"; + OpenVDB_import_grid_fl(reader, name, &fuel, sds->res); + name = (!sds->wt) ? "react" : "react low"; + OpenVDB_import_grid_fl(reader, name, &react, sds->res); + } + + if (fluid_fields & SM_ACTIVE_COLORS) { + name = (!sds->wt) ? "color" : "color low"; + OpenVDB_import_grid_vec(reader, name, &r, &g, &b, sds->res); + } + + OpenVDB_import_grid_vec(reader, "velocity", &vx, &vy, &vz, sds->res); + OpenVDB_import_grid_ch(reader, "obstacles", &obstacles, sds->res); + } + + if (sds->wt) { + float *dens, *react, *fuel, *flame, *tcu, *tcv, *tcw, *r, *g, *b; + + smoke_turbulence_export(sds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw); + + OpenVDB_import_grid_fl(reader, "density", &dens, sds->res_wt); + + if (fluid_fields & SM_ACTIVE_FIRE) { + OpenVDB_import_grid_fl(reader, "flame", &flame, sds->res_wt); + OpenVDB_import_grid_fl(reader, "fuel", &fuel, sds->res_wt); + OpenVDB_import_grid_fl(reader, "react", &react, sds->res_wt); + } + + if (fluid_fields & SM_ACTIVE_COLORS) { + OpenVDB_import_grid_vec(reader, "color", &r, &g, &b, sds->res_wt); + } + + OpenVDB_import_grid_vec(reader, "texture coordinates", &tcu, &tcv, &tcw, sds->res); + } + + OpenVDBReader_free(reader); + + return 1; +} +#endif + #else // WITH_SMOKE static int ptcache_smoke_totpoint(void *UNUSED(smoke_v), int UNUSED(cfra)) { return 0; } static void ptcache_smoke_error(void *UNUSED(smoke_v), const char *UNUSED(message)) { } @@ -894,6 +1166,20 @@ static int ptcache_smoke_read(PTCacheFile *UNUSED(pf), void *UNUSED(smoke_v)) { static int ptcache_smoke_write(PTCacheFile *UNUSED(pf), void *UNUSED(smoke_v)) { return 0; } #endif // WITH_SMOKE +#if !defined(WITH_SMOKE) || !defined(WITH_OPENVDB) +static int ptcache_smoke_openvdb_write(struct OpenVDBWriter *writer, void *smoke_v) +{ + UNUSED_VARS(writer, smoke_v); + return 0; +} + +static int ptcache_smoke_openvdb_read(struct OpenVDBReader *reader, void *smoke_v) +{ + UNUSED_VARS(reader, smoke_v); + return 0; +} +#endif + static int ptcache_dynamicpaint_totpoint(void *sd, int UNUSED(cfra)) { DynamicPaintSurface *surface = (DynamicPaintSurface*)sd; @@ -1113,6 +1399,9 @@ void BKE_ptcache_id_from_softbody(PTCacheID *pid, Object *ob, SoftBody *sb) pid->write_stream = NULL; pid->read_stream = NULL; + pid->write_openvdb_stream = NULL; + pid->read_openvdb_stream = NULL; + pid->write_extra_data = NULL; pid->read_extra_data = NULL; pid->interpolate_extra_data = NULL; @@ -1127,6 +1416,7 @@ void BKE_ptcache_id_from_softbody(PTCacheID *pid, Object *ob, SoftBody *sb) pid->default_step = 10; pid->max_step = 20; + pid->file_type = PTCACHE_FILE_PTCACHE; } void BKE_ptcache_id_from_particles(PTCacheID *pid, Object *ob, ParticleSystem *psys) { @@ -1154,6 +1444,9 @@ void BKE_ptcache_id_from_particles(PTCacheID *pid, Object *ob, ParticleSystem *p pid->write_stream = NULL; pid->read_stream = NULL; + pid->write_openvdb_stream = NULL; + pid->read_openvdb_stream = NULL; + pid->write_extra_data = NULL; pid->read_extra_data = NULL; pid->interpolate_extra_data = NULL; @@ -1185,6 +1478,7 @@ void BKE_ptcache_id_from_particles(PTCacheID *pid, Object *ob, ParticleSystem *p pid->default_step = 10; pid->max_step = 20; + pid->file_type = PTCACHE_FILE_PTCACHE; } void BKE_ptcache_id_from_cloth(PTCacheID *pid, Object *ob, ClothModifierData *clmd) { @@ -1204,6 +1498,9 @@ void BKE_ptcache_id_from_cloth(PTCacheID *pid, Object *ob, ClothModifierData *cl pid->read_point = ptcache_cloth_read; pid->interpolate_point = ptcache_cloth_interpolate; + pid->write_openvdb_stream = NULL; + pid->read_openvdb_stream = NULL; + pid->write_stream = NULL; pid->read_stream = NULL; @@ -1219,6 +1516,7 @@ void BKE_ptcache_id_from_cloth(PTCacheID *pid, Object *ob, ClothModifierData *cl pid->default_step = 1; pid->max_step = 1; + pid->file_type = PTCACHE_FILE_PTCACHE; } void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct SmokeModifierData *smd) { @@ -1246,6 +1544,9 @@ void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct SmokeMo pid->read_stream = ptcache_smoke_read; pid->write_stream = ptcache_smoke_write; + pid->write_openvdb_stream = ptcache_smoke_openvdb_write; + pid->read_openvdb_stream = ptcache_smoke_openvdb_read; + pid->write_extra_data = NULL; pid->read_extra_data = NULL; pid->interpolate_extra_data = NULL; @@ -1263,6 +1564,7 @@ void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct SmokeMo pid->default_step = 1; pid->max_step = 1; + pid->file_type = smd->domain->cache_file_format; } void BKE_ptcache_id_from_dynamicpaint(PTCacheID *pid, Object *ob, DynamicPaintSurface *surface) @@ -1286,6 +1588,9 @@ void BKE_ptcache_id_from_dynamicpaint(PTCacheID *pid, Object *ob, DynamicPaintSu pid->write_stream = ptcache_dynamicpaint_write; pid->read_stream = ptcache_dynamicpaint_read; + pid->write_openvdb_stream = NULL; + pid->read_openvdb_stream = NULL; + pid->write_extra_data = NULL; pid->read_extra_data = NULL; pid->interpolate_extra_data = NULL; @@ -1300,6 +1605,7 @@ void BKE_ptcache_id_from_dynamicpaint(PTCacheID *pid, Object *ob, DynamicPaintSu pid->default_step = 1; pid->max_step = 1; + pid->file_type = PTCACHE_FILE_PTCACHE; } void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, Object *ob, RigidBodyWorld *rbw) @@ -1322,6 +1628,9 @@ void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, Object *ob, RigidBodyWorld *r pid->write_stream = NULL; pid->read_stream = NULL; + + pid->write_openvdb_stream = NULL; + pid->read_openvdb_stream = NULL; pid->write_extra_data = NULL; pid->read_extra_data = NULL; @@ -1337,6 +1646,7 @@ void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, Object *ob, RigidBodyWorld *r pid->default_step = 1; pid->max_step = 1; + pid->file_type = PTCACHE_FILE_PTCACHE; } void BKE_ptcache_ids_from_object(ListBase *lb, Object *ob, Scene *scene, int duplis) @@ -1429,6 +1739,38 @@ void BKE_ptcache_ids_from_object(ListBase *lb, Object *ob, Scene *scene, int dup /* File handling */ +static const char *ptcache_file_extension(const PTCacheID *pid) +{ + switch (pid->file_type) { + default: + case PTCACHE_FILE_PTCACHE: + return PTCACHE_EXT; + case PTCACHE_FILE_OPENVDB: + return ".vdb"; + } +} + +/** + * Similar to #BLI_path_frame_get, but takes into account the stack-index which is after the frame. + */ +static int ptcache_frame_from_filename(const char *filename, const char *ext) +{ + const int frame_len = 6; + const int ext_len = frame_len + strlen(ext); + const int len = strlen(filename); + + /* could crash if trying to copy a string out of this range */ + if (len > ext_len) { + /* using frame_len here gives compile error (vla) */ + char num[/* frame_len */6 + 1]; + BLI_strncpy(num, filename + len - ext_len, sizeof(num)); + + return atoi(num); + } + + return -1; +} + /* Takes an Object ID and returns a unique name * - id: object id * - cfra: frame for the cache, can be negative @@ -1507,18 +1849,19 @@ static int ptcache_filename(PTCacheID *pid, char *filename, int cfra, short do_p } if (do_ext) { - if (pid->cache->index < 0) pid->cache->index = pid->stack_index = BKE_object_insert_ptcache(pid->ob); + const char *ext = ptcache_file_extension(pid); + if (pid->cache->flag & PTCACHE_EXTERNAL) { if (pid->cache->index >= 0) - BLI_snprintf(newname, MAX_PTCACHE_FILE, "_%06d_%02u"PTCACHE_EXT, cfra, pid->stack_index); /* always 6 chars */ + BLI_snprintf(newname, MAX_PTCACHE_FILE, "_%06d_%02u%s", cfra, pid->stack_index, ext); /* always 6 chars */ else - BLI_snprintf(newname, MAX_PTCACHE_FILE, "_%06d"PTCACHE_EXT, cfra); /* always 6 chars */ + BLI_snprintf(newname, MAX_PTCACHE_FILE, "_%06d%s", cfra, ext); /* always 6 chars */ } else { - BLI_snprintf(newname, MAX_PTCACHE_FILE, "_%06d_%02u"PTCACHE_EXT, cfra, pid->stack_index); /* always 6 chars */ + BLI_snprintf(newname, MAX_PTCACHE_FILE, "_%06d_%02u%s", cfra, pid->stack_index, ext); /* always 6 chars */ } len += 16; } @@ -2156,6 +2499,36 @@ static int ptcache_read_stream(PTCacheID *pid, int cfra) return error == 0; } + +static int ptcache_read_openvdb_stream(PTCacheID *pid, int cfra) +{ +#ifdef WITH_OPENVDB + char filename[FILE_MAX * 2]; + + /* save blend file before using disk pointcache */ + if (!G.relbase_valid && (pid->cache->flag & PTCACHE_EXTERNAL) == 0) + return 0; + + ptcache_filename(pid, filename, cfra, 1, 1); + + if (!BLI_exists(filename)) { + return 0; + } + + struct OpenVDBReader *reader = OpenVDBReader_create(); + OpenVDBReader_open(reader, filename); + + if (!pid->read_openvdb_stream(reader, pid->calldata)) { + return 0; + } + + return 1; +#else + UNUSED_VARS(pid, cfra); + return 0; +#endif +} + static int ptcache_read(PTCacheID *pid, int cfra) { PTCacheMem *pm = NULL; @@ -2297,8 +2670,12 @@ int BKE_ptcache_read(PTCacheID *pid, float cfra) return 0; if (cfra1) { - - if (pid->read_stream) { + if (pid->file_type == PTCACHE_FILE_OPENVDB && pid->read_openvdb_stream) { + if (!ptcache_read_openvdb_stream(pid, cfra1)) { + return 0; + } + } + else if (pid->read_stream) { if (!ptcache_read_stream(pid, cfra1)) return 0; } @@ -2307,8 +2684,12 @@ int BKE_ptcache_read(PTCacheID *pid, float cfra) } if (cfra2) { - - if (pid->read_stream) { + if (pid->file_type == PTCACHE_FILE_OPENVDB && pid->read_openvdb_stream) { + if (!ptcache_read_openvdb_stream(pid, cfra2)) { + return 0; + } + } + else if (pid->read_stream) { if (!ptcache_read_stream(pid, cfra2)) return 0; } @@ -2374,6 +2755,28 @@ static int ptcache_write_stream(PTCacheID *pid, int cfra, int totpoint) return error == 0; } +static int ptcache_write_openvdb_stream(PTCacheID *pid, int cfra) +{ +#ifdef WITH_OPENVDB + struct OpenVDBWriter *writer = OpenVDBWriter_create(); + char filename[FILE_MAX * 2]; + + BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_FRAME, cfra); + + ptcache_filename(pid, filename, cfra, 1, 1); + BLI_make_existing_file(filename); + + int error = pid->write_openvdb_stream(writer, pid->calldata); + + OpenVDBWriter_write(writer, filename); + OpenVDBWriter_free(writer); + + return error == 0; +#else + UNUSED_VARS(pid, cfra); + return 0; +#endif +} static int ptcache_write(PTCacheID *pid, int cfra, int overwrite) { PointCache *cache = pid->cache; @@ -2505,7 +2908,10 @@ int BKE_ptcache_write(PTCacheID *pid, unsigned int cfra) if (ptcache_write_needed(pid, cfra, &overwrite)==0) return 0; - if (pid->write_stream) { + if (pid->file_type == PTCACHE_FILE_OPENVDB && pid->write_openvdb_stream) { + ptcache_write_openvdb_stream(pid, cfra); + } + else if (pid->write_stream) { ptcache_write_stream(pid, cfra, totpoint); } else if (pid->write_point) { @@ -2563,7 +2969,9 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, unsigned int cfra) #endif /*if (!G.relbase_valid) return; *//* save blend file before using pointcache */ - + + const char *fext = ptcache_file_extension(pid); + /* clear all files in the temp dir with the prefix of the ID and the ".bphys" suffix */ switch (mode) { case PTCACHE_CLEAR_ALL: @@ -2585,7 +2993,7 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, unsigned int cfra) len += 1; } - BLI_snprintf(ext, sizeof(ext), "_%02u"PTCACHE_EXT, pid->stack_index); + BLI_snprintf(ext, sizeof(ext), "_%02u%s", pid->stack_index, fext); while ((de = readdir(dir)) != NULL) { if (strstr(de->d_name, ext)) { /* do we have the right extension?*/ @@ -2597,13 +3005,9 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, unsigned int cfra) } else { /* read the number of the file */ - unsigned int frame, len2 = (int)strlen(de->d_name); - char num[7]; + const int frame = ptcache_frame_from_filename(de->d_name, ext); - if (len2 > 15) { /* could crash if trying to copy a string out of this range*/ - BLI_strncpy(num, de->d_name + (strlen(de->d_name) - 15), sizeof(num)); - frame = atoi(num); - + if (frame != -1) { if ((mode == PTCACHE_CLEAR_BEFORE && frame < cfra) || (mode == PTCACHE_CLEAR_AFTER && frame > cfra)) { @@ -2791,21 +3195,18 @@ void BKE_ptcache_id_time(PTCacheID *pid, Scene *scene, float cfra, int *startfra if (dir==NULL) return; - BLI_snprintf(ext, sizeof(ext), "_%02u"PTCACHE_EXT, pid->stack_index); + const char *fext = ptcache_file_extension(pid); + + BLI_snprintf(ext, sizeof(ext), "_%02u%s", pid->stack_index, fext); while ((de = readdir(dir)) != NULL) { if (strstr(de->d_name, ext)) { /* do we have the right extension?*/ if (STREQLEN(filename, de->d_name, len)) { /* do we have the right prefix */ /* read the number of the file */ - unsigned int frame, len2 = (int)strlen(de->d_name); - char num[7]; - - if (len2 > 15) { /* could crash if trying to copy a string out of this range*/ - BLI_strncpy(num, de->d_name + (strlen(de->d_name) - 15), sizeof(num)); - frame = atoi(num); - - if (frame >= sta && frame <= end) - cache->cached_frames[frame-sta] = 1; + const int frame = ptcache_frame_from_filename(de->d_name, ext); + + if ((frame != -1) && (frame >= sta && frame <= end)) { + cache->cached_frames[frame-sta] = 1; } } } @@ -3466,7 +3867,9 @@ void BKE_ptcache_disk_cache_rename(PTCacheID *pid, const char *name_src, const c return; } - BLI_snprintf(ext, sizeof(ext), "_%02u"PTCACHE_EXT, pid->stack_index); + const char *fext = ptcache_file_extension(pid); + + BLI_snprintf(ext, sizeof(ext), "_%02u%s", pid->stack_index, fext); /* put new name into cache */ BLI_strncpy(pid->cache->name, name_dst, sizeof(pid->cache->name)); @@ -3475,13 +3878,9 @@ void BKE_ptcache_disk_cache_rename(PTCacheID *pid, const char *name_src, const c if (strstr(de->d_name, ext)) { /* do we have the right extension?*/ if (STREQLEN(old_filename, de->d_name, len)) { /* do we have the right prefix */ /* read the number of the file */ - int frame, len2 = (int)strlen(de->d_name); - char num[7]; - - if (len2 > 15) { /* could crash if trying to copy a string out of this range*/ - BLI_strncpy(num, de->d_name + (strlen(de->d_name) - 15), sizeof(num)); - frame = atoi(num); + const int frame = ptcache_frame_from_filename(de->d_name, ext); + if (frame != -1) { BLI_join_dirfile(old_path_full, sizeof(old_path_full), path, de->d_name); ptcache_filename(pid, new_path_full, frame, 1, 1); BLI_rename(old_path_full, new_path_full); @@ -3521,22 +3920,20 @@ void BKE_ptcache_load_external(PTCacheID *pid) if (dir==NULL) return; + const char *fext = ptcache_file_extension(pid); + if (cache->index >= 0) - BLI_snprintf(ext, sizeof(ext), "_%02d"PTCACHE_EXT, cache->index); + BLI_snprintf(ext, sizeof(ext), "_%02d%s", cache->index, fext); else - BLI_strncpy(ext, PTCACHE_EXT, sizeof(ext)); + BLI_strncpy(ext, fext, sizeof(ext)); while ((de = readdir(dir)) != NULL) { if (strstr(de->d_name, ext)) { /* do we have the right extension?*/ if (STREQLEN(filename, de->d_name, len)) { /* do we have the right prefix */ /* read the number of the file */ - int frame, len2 = (int)strlen(de->d_name); - char num[7]; - - if (len2 > 15) { /* could crash if trying to copy a string out of this range*/ - BLI_strncpy(num, de->d_name + (strlen(de->d_name) - 15), sizeof(num)); - frame = atoi(num); + const int frame = ptcache_frame_from_filename(de->d_name, ext); + if (frame != -1) { if (frame) { start = MIN2(start, frame); end = MAX2(end, frame); diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c index 2d3fa2a3818..c7215cc7d4c 100644 --- a/source/blender/blenkernel/intern/smoke.c +++ b/source/blender/blenkernel/intern/smoke.c @@ -527,6 +527,14 @@ void smokeModifier_createType(struct SmokeModifierData *smd) smd->domain->viewsettings = MOD_SMOKE_VIEW_SHOWBIG; smd->domain->effector_weights = BKE_add_effector_weights(NULL); + +#ifdef WITH_OPENVDB_BLOSC + smd->domain->openvdb_comp = VDB_COMPRESSION_BLOSC; +#else + smd->domain->openvdb_comp = VDB_COMPRESSION_ZIP; +#endif + smd->domain->data_depth = 0; + smd->domain->cache_file_format = PTCACHE_FILE_PTCACHE; } else if (smd->type & MOD_SMOKE_TYPE_FLOW) { @@ -617,6 +625,9 @@ void smokeModifier_copy(struct SmokeModifierData *smd, struct SmokeModifierData MEM_freeN(tsmd->domain->effector_weights); tsmd->domain->effector_weights = MEM_dupallocN(smd->domain->effector_weights); + tsmd->domain->openvdb_comp = smd->domain->openvdb_comp; + tsmd->domain->data_depth = smd->domain->data_depth; + tsmd->domain->cache_file_format = smd->domain->cache_file_format; } else if (tsmd->flow) { tsmd->flow->psys = smd->flow->psys; diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 732d699d48f..84cb28b3fc0 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -7812,9 +7812,9 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short /* draw adaptive domain bounds */ if ((sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) && !render_override) { - float p0[3], p1[3]; - BoundBox bb; /* draw domain max bounds */ + BoundBox bb; + float p0[3], p1[3]; VECSUBFAC(p0, sds->p0, sds->cell_size, sds->adapt_res); VECADDFAC(p1, sds->p1, sds->cell_size, sds->adapt_res); BKE_boundbox_init_from_minmax(&bb, p0, p1); @@ -7825,6 +7825,20 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short BKE_boundbox_init_from_minmax(&bb, sds->p0, sds->p1); draw_box(bb.vec); #endif + + + /* draw a single voxel to hint the user about the resolution of the fluid */ + copy_v3_v3(p0, sds->p0); + + if (sds->flags & MOD_SMOKE_HIGHRES) { + madd_v3_v3v3fl(p1, p0, sds->cell_size, 1.0f / (sds->amplify + 1)); + } + else { + add_v3_v3v3(p1, p0, sds->cell_size); + } + + BKE_boundbox_init_from_minmax(&bb, p0, p1); + draw_box(bb.vec, false); } /* don't show smoke before simulation starts, this could be made an option in the future */ diff --git a/source/blender/makesdna/DNA_smoke_types.h b/source/blender/makesdna/DNA_smoke_types.h index 5e011678fee..76de8443faa 100644 --- a/source/blender/makesdna/DNA_smoke_types.h +++ b/source/blender/makesdna/DNA_smoke_types.h @@ -77,6 +77,12 @@ enum { #define SM_ACTIVE_COLORS (1<<2) #define SM_ACTIVE_COLOR_SET (1<<3) +enum { + VDB_COMPRESSION_BLOSC = 0, + VDB_COMPRESSION_ZIP = 1, + VDB_COMPRESSION_NONE = 2, +}; + typedef struct SmokeDomainSettings { struct SmokeModifierData *smd; /* for fast RNA access */ struct FLUID_3D *fluid; @@ -103,6 +109,8 @@ typedef struct SmokeDomainSettings { float obj_shift_f[3]; /* how much object has shifted since previous smoke frame (used to "lock" domain while drawing) */ float imat[4][4]; /* domain object imat */ float obmat[4][4]; /* domain obmat */ + float fluidmat[4][4]; /* low res fluid matrix */ + float fluidmat_wt[4][4]; /* high res fluid matrix */ int base_res[3]; /* initial "non-adapted" resolution */ int res_min[3]; /* cell min */ @@ -129,8 +137,14 @@ typedef struct SmokeDomainSettings { float strength; int res_wt[3]; float dx_wt; + /* point cache options */ int cache_comp; int cache_high_comp; + /* OpenVDB cache options */ + int openvdb_comp; + char cache_file_format; + char data_depth; + char pad[2]; /* Smoke uses only one cache from now on (index [0]), but keeping the array for now for reading old files. */ struct PointCache *point_cache[2]; /* definition is in DNA_object_force.h */ diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt index 987b594421f..31bf0c9389b 100644 --- a/source/blender/makesrna/intern/CMakeLists.txt +++ b/source/blender/makesrna/intern/CMakeLists.txt @@ -311,6 +311,14 @@ if(WITH_OPENSUBDIV) add_definitions(-DWITH_OPENSUBDIV) endif() +if(WITH_OPENVDB) + add_definitions(-DWITH_OPENVDB) + + if(WITH_OPENVDB_BLOSC) + add_definitions(-DWITH_OPENVDB_BLOSC) + endif() +endif() + # Build makesrna executable blender_include_dirs( . diff --git a/source/blender/makesrna/intern/rna_smoke.c b/source/blender/makesrna/intern/rna_smoke.c index 539f3c192be..ba3198a4843 100644 --- a/source/blender/makesrna/intern/rna_smoke.c +++ b/source/blender/makesrna/intern/rna_smoke.c @@ -35,6 +35,7 @@ #include "BKE_modifier.h" #include "BKE_smoke.h" +#include "BKE_pointcache.h" #include "BLI_threads.h" @@ -332,6 +333,15 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; + static EnumPropertyItem prop_compression_items[] = { + { VDB_COMPRESSION_ZIP, "ZIP", 0, "Zip", "Effective but slow compression" }, +#ifdef WITH_OPENVDB_BLOSC + { VDB_COMPRESSION_BLOSC, "BLOSC", 0, "Blosc", "Multithreaded compression, similar in size and quality as 'Zip'" }, +#endif + { VDB_COMPRESSION_NONE, "NONE", 0, "None", "Do not use any compression" }, + { 0, NULL, 0, NULL, NULL } + }; + static EnumPropertyItem smoke_cache_comp_items[] = { {SM_CACHE_LIGHT, "CACHELIGHT", 0, "Light", "Fast but not so effective compression"}, {SM_CACHE_HEAVY, "CACHEHEAVY", 0, "Heavy", "Effective but slow compression"}, @@ -345,6 +355,12 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; + static EnumPropertyItem smoke_data_depth_items[] = { + {16, "16", 0, "Float (Half)", "Half float (16 bit data)"}, + {0, "32", 0, "Float (Full)", "Full float (32 bit data)"}, /* default */ + {0, NULL, 0, NULL, NULL}, + }; + static EnumPropertyItem smoke_domain_colli_items[] = { {SM_BORDER_OPEN, "BORDEROPEN", 0, "Open", "Smoke doesn't collide with any border"}, {SM_BORDER_VERTICAL, "BORDERVERTICAL", 0, "Vertically Open", @@ -353,6 +369,14 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; + static EnumPropertyItem cache_file_type_items[] = { + {PTCACHE_FILE_PTCACHE, "POINTCACHE", 0, "Point Cache", "Blender specific point cache file format"}, +#ifdef WITH_OPENVDB + {PTCACHE_FILE_OPENVDB, "OPENVDB", 0, "OpenVDB", "OpenVDB file format"}, +#endif + {0, NULL, 0, NULL, NULL} + }; + srna = RNA_def_struct(brna, "SmokeDomainSettings", NULL); RNA_def_struct_ui_text(srna, "Domain Settings", "Smoke domain settings"); RNA_def_struct_sdna(srna, "SmokeDomainSettings"); @@ -463,6 +487,19 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna) RNA_def_property_enum_items(prop, smoke_cache_comp_items); RNA_def_property_ui_text(prop, "Cache Compression", "Compression method to be used"); + prop = RNA_def_property(srna, "openvdb_cache_compress_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "openvdb_comp"); + RNA_def_property_enum_items(prop, prop_compression_items); + RNA_def_property_ui_text(prop, "Compression", "Compression method to be used"); + + prop = RNA_def_property(srna, "data_depth", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_bitflag_sdna(prop, NULL, "data_depth"); + RNA_def_property_enum_items(prop, smoke_data_depth_items); + RNA_def_property_ui_text(prop, "Data Depth", + "Bit depth for writing all scalar (including vector) " + "lower values reduce file size"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL); + prop = RNA_def_property(srna, "collision_extents", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "border_collisions"); RNA_def_property_enum_items(prop, smoke_domain_colli_items); @@ -601,6 +638,12 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Threshold", "Maximum amount of fluid cell can contain before it is considered empty"); RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache"); + + prop = RNA_def_property(srna, "cache_file_format", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "cache_file_format"); + RNA_def_property_enum_items(prop, cache_file_type_items); + RNA_def_property_ui_text(prop, "File Format", "Select the file format to be used for caching"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache"); } static void rna_def_smoke_flow_settings(BlenderRNA *brna) diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt index cbfbe0a8768..5b39dbb062b 100644 --- a/source/blender/python/intern/CMakeLists.txt +++ b/source/blender/python/intern/CMakeLists.txt @@ -54,6 +54,7 @@ set(SRC bpy_app_handlers.c bpy_app_ocio.c bpy_app_oiio.c + bpy_app_openvdb.c bpy_app_sdl.c bpy_app_translations.c bpy_driver.c @@ -84,6 +85,7 @@ set(SRC bpy_app_handlers.h bpy_app_ocio.h bpy_app_oiio.h + bpy_app_openvdb.h bpy_app_sdl.h bpy_app_translations.h bpy_driver.h @@ -267,6 +269,13 @@ if(WITH_OPENCOLORIO) add_definitions(-DWITH_OCIO) endif() +if(WITH_OPENVDB) + add_definitions(-DWITH_OPENVDB) + list(APPEND INC + ../../../../intern/openvdb + ) +endif() + if(WITH_OPENIMAGEIO) add_definitions(-DWITH_OPENIMAGEIO) list(APPEND INC diff --git a/source/blender/python/intern/bpy_app.c b/source/blender/python/intern/bpy_app.c index a0ea991fd05..595bb7b0f22 100644 --- a/source/blender/python/intern/bpy_app.c +++ b/source/blender/python/intern/bpy_app.c @@ -36,6 +36,7 @@ #include "bpy_app_ffmpeg.h" #include "bpy_app_ocio.h" #include "bpy_app_oiio.h" +#include "bpy_app_openvdb.h" #include "bpy_app_sdl.h" #include "bpy_app_build_options.h" @@ -106,6 +107,7 @@ static PyStructSequence_Field app_info_fields[] = { {(char *)"ffmpeg", (char *)"FFmpeg library information backend"}, {(char *)"ocio", (char *)"OpenColorIO library information backend"}, {(char *)"oiio", (char *)"OpenImageIO library information backend"}, + {(char *)"openvdb", (char *)"OpenVDB library information backend"}, {(char *)"sdl", (char *)"SDL library information backend"}, {(char *)"build_options", (char *)"A set containing most important enabled optional build features"}, {(char *)"handlers", (char *)"Application handler callbacks"}, @@ -183,6 +185,7 @@ static PyObject *make_app_info(void) SetObjItem(BPY_app_ffmpeg_struct()); SetObjItem(BPY_app_ocio_struct()); SetObjItem(BPY_app_oiio_struct()); + SetObjItem(BPY_app_openvdb_struct()); SetObjItem(BPY_app_sdl_struct()); SetObjItem(BPY_app_build_options_struct()); SetObjItem(BPY_app_handlers_struct()); diff --git a/source/blender/python/intern/bpy_app_build_options.c b/source/blender/python/intern/bpy_app_build_options.c index 975d76ca42d..692ebf552c7 100644 --- a/source/blender/python/intern/bpy_app_build_options.c +++ b/source/blender/python/intern/bpy_app_build_options.c @@ -69,6 +69,7 @@ static PyStructSequence_Field app_builtopts_info_fields[] = { {(char *)"opencolorio", NULL}, {(char *)"player", NULL}, {(char *)"openmp", NULL}, + {(char *)"openvdb", NULL}, {NULL} }; @@ -303,6 +304,12 @@ static PyObject *make_builtopts_info(void) SetObjIncref(Py_False); #endif +#ifdef WITH_OPENVDB + SetObjIncref(Py_True); +#else + SetObjIncref(Py_False); +#endif + #undef SetObjIncref return builtopts_info; diff --git a/source/blender/python/intern/bpy_app_openvdb.c b/source/blender/python/intern/bpy_app_openvdb.c new file mode 100644 index 00000000000..8a24aaf0555 --- /dev/null +++ b/source/blender/python/intern/bpy_app_openvdb.c @@ -0,0 +1,117 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2015 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Kevin Dietrich + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/intern/bpy_app_openvdb.c + * \ingroup pythonintern + */ + +#include <Python.h> +#include "BLI_utildefines.h" + +#include "bpy_app_openvdb.h" + +#ifdef WITH_OPENVDB +# include "openvdb_capi.h" +#endif + +static PyTypeObject BlenderAppOVDBType; + +static PyStructSequence_Field app_openvdb_info_fields[] = { + {(char *)"supported", (char *)("Boolean, True when Blender is built with OpenVDB support")}, + {(char *)("version"), (char *)("The OpenVDB version as a tuple of 3 numbers")}, + {(char *)("version_string"), (char *)("The OpenVDB version formatted as a string")}, + {NULL} +}; + +static PyStructSequence_Desc app_openvdb_info_desc = { + (char *)"bpy.app.openvdb", /* name */ + (char *)"This module contains information about OpenVDB blender is linked against", /* doc */ + app_openvdb_info_fields, /* fields */ + ARRAY_SIZE(app_openvdb_info_fields) - 1 +}; + +static PyObject *make_openvdb_info(void) +{ + PyObject *openvdb_info; + int pos = 0; + +#ifdef WITH_OPENVDB + int curversion; +#endif + + openvdb_info = PyStructSequence_New(&BlenderAppOVDBType); + if (openvdb_info == NULL) { + return NULL; + } + +#ifndef WITH_OPENVDB +#define SetStrItem(str) \ + PyStructSequence_SET_ITEM(openvdb_info, pos++, PyUnicode_FromString(str)) +#endif + +#define SetObjItem(obj) \ + PyStructSequence_SET_ITEM(openvdb_info, pos++, obj) + +#ifdef WITH_OPENVDB + curversion = OpenVDB_getVersionHex(); + SetObjItem(PyBool_FromLong(1)); + SetObjItem(Py_BuildValue("(iii)", + curversion >> 24, (curversion >> 16) % 256, (curversion >> 8) % 256)); + SetObjItem(PyUnicode_FromFormat("%2d, %2d, %2d", + curversion >> 24, (curversion >> 16) % 256, (curversion >> 8) % 256)); +#else + SetObjItem(PyBool_FromLong(0)); + SetObjItem(Py_BuildValue("(iii)", 0, 0, 0)); + SetStrItem("Unknown"); +#endif + + if (PyErr_Occurred()) { + Py_CLEAR(openvdb_info); + return NULL; + } + +#undef SetStrItem +#undef SetObjItem + + return openvdb_info; +} + +PyObject *BPY_app_openvdb_struct(void) +{ + PyObject *ret; + + PyStructSequence_InitType(&BlenderAppOVDBType, &app_openvdb_info_desc); + + ret = make_openvdb_info(); + + /* prevent user from creating new instances */ + BlenderAppOVDBType.tp_init = NULL; + BlenderAppOVDBType.tp_new = NULL; + BlenderAppOVDBType.tp_hash = (hashfunc)_Py_HashPointer; /* without this we can't do set(sys.modules) [#29635] */ + + return ret; +} diff --git a/source/blender/python/intern/bpy_app_openvdb.h b/source/blender/python/intern/bpy_app_openvdb.h new file mode 100644 index 00000000000..12fa54ea7a3 --- /dev/null +++ b/source/blender/python/intern/bpy_app_openvdb.h @@ -0,0 +1,38 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2015 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Kevin Dietrich + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/intern/bpy_app_openvdb.h + * \ingroup pythonintern + */ + +#ifndef __BPY_APP_OPENVDB_H__ +#define __BPY_APP_OPENVDB_H__ + +PyObject *BPY_app_openvdb_struct(void); + +#endif /* __BPY_APP_OPENVDB_H__ */ + diff --git a/source/blenderplayer/CMakeLists.txt b/source/blenderplayer/CMakeLists.txt index e8c710e68ae..65432fc3f88 100644 --- a/source/blenderplayer/CMakeLists.txt +++ b/source/blenderplayer/CMakeLists.txt @@ -218,6 +218,10 @@ endif() list(APPEND BLENDER_SORTED_LIBS bf_intern_opensubdiv) endif() + if(WITH_OPENVDB) + list(APPEND BLENDER_SORTED_LIBS bf_intern_openvdb) + endif() + foreach(SORTLIB ${BLENDER_SORTED_LIBS}) set(REMLIB ${SORTLIB}) foreach(SEARCHLIB ${BLENDER_LINK_LIBS}) |