From edf4cb8b673edd37dd38dc79dd92dfdcd1488ba6 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Wed, 24 May 2023 08:45:31 +0200 Subject: [PATCH] Geometry Nodes: store path to simulation bake in modifier This adds `char *simulation_bake_directory` to the nodes modifier. The path is automatically generated the first time the modifier is baked. It is _not_ automatically changed afterwards. The path is relative to the .blend file by default. For now, the path is not exposed in the UI or Python API. This fixes issues where renaming objects/modifiers can cause the baked data to not work anymore. Pull Request: https://projects.blender.org/blender/blender/pulls/108201 --- .../blenkernel/BKE_simulation_state.hh | 2 +- .../BKE_simulation_state_serialize.hh | 9 ++-- .../blenkernel/intern/simulation_state.cc | 13 +++-- .../intern/simulation_state_serialize.cc | 49 ++++++------------- .../blenloader/intern/versioning_300.cc | 17 +++++++ .../editors/object/object_bake_simulation.cc | 46 ++++++++++------- source/blender/makesdna/DNA_modifier_types.h | 5 ++ source/blender/modifiers/intern/MOD_nodes.cc | 19 +++++-- 8 files changed, 96 insertions(+), 64 deletions(-) diff --git a/source/blender/blenkernel/BKE_simulation_state.hh b/source/blender/blenkernel/BKE_simulation_state.hh index c72a50c3568..63d514d3a91 100644 --- a/source/blender/blenkernel/BKE_simulation_state.hh +++ b/source/blender/blenkernel/BKE_simulation_state.hh @@ -162,7 +162,7 @@ class ModifierSimulationCache { CacheState cache_state_ = CacheState::Valid; bool failed_finding_bake_ = false; - void try_discover_bake(StringRefNull meta_dir, StringRefNull bdata_dir); + void try_discover_bake(StringRefNull absolute_bake_dir); bool has_state_at_frame(const SubFrame &frame) const; bool has_states() const; diff --git a/source/blender/blenkernel/BKE_simulation_state_serialize.hh b/source/blender/blenkernel/BKE_simulation_state_serialize.hh index d9cfc773514..8ad6b64a5b3 100644 --- a/source/blender/blenkernel/BKE_simulation_state_serialize.hh +++ b/source/blender/blenkernel/BKE_simulation_state_serialize.hh @@ -143,12 +143,11 @@ class DiskBDataWriter : public BDataWriter { }; /** - * Get the directory that contains all baked simulation data for the given modifier. This is a - * parent directory of the two directories below. + * Get the directory that contains all baked simulation data for the given modifier. */ -std::string get_bake_directory(const Main &bmain, const Object &object, const ModifierData &md); -std::string get_bdata_directory(const Main &bmain, const Object &object, const ModifierData &md); -std::string get_meta_directory(const Main &bmain, const Object &object, const ModifierData &md); +std::string get_default_modifier_bake_directory(const Main &bmain, + const Object &object, + const ModifierData &md); /** * Encode the simulation state in a #DictionaryValue which also contains references to external diff --git a/source/blender/blenkernel/intern/simulation_state.cc b/source/blender/blenkernel/intern/simulation_state.cc index c66a8b7aa8e..ced43350276 100644 --- a/source/blender/blenkernel/intern/simulation_state.cc +++ b/source/blender/blenkernel/intern/simulation_state.cc @@ -37,19 +37,24 @@ StringSimulationStateItem::StringSimulationStateItem(std::string value) : value_ { } -void ModifierSimulationCache::try_discover_bake(const StringRefNull meta_dir, - const StringRefNull bdata_dir) +void ModifierSimulationCache::try_discover_bake(const StringRefNull absolute_bake_dir) { if (failed_finding_bake_) { return; } - if (!BLI_is_dir(meta_dir.c_str()) || !BLI_is_dir(bdata_dir.c_str())) { + + char meta_dir[FILE_MAX]; + BLI_path_join(meta_dir, sizeof(meta_dir), absolute_bake_dir.c_str(), "meta"); + char bdata_dir[FILE_MAX]; + BLI_path_join(bdata_dir, sizeof(bdata_dir), absolute_bake_dir.c_str(), "bdata"); + + if (!BLI_is_dir(meta_dir) || !BLI_is_dir(bdata_dir)) { failed_finding_bake_ = true; return; } direntry *dir_entries = nullptr; - const int dir_entries_num = BLI_filelist_dir_contents(meta_dir.c_str(), &dir_entries); + const int dir_entries_num = BLI_filelist_dir_contents(meta_dir, &dir_entries); BLI_SCOPED_DEFER([&]() { BLI_filelist_free(dir_entries, dir_entries_num); }); if (dir_entries_num == 0) { diff --git a/source/blender/blenkernel/intern/simulation_state_serialize.cc b/source/blender/blenkernel/intern/simulation_state_serialize.cc index 070ca85901d..4a51983228c 100644 --- a/source/blender/blenkernel/intern/simulation_state_serialize.cc +++ b/source/blender/blenkernel/intern/simulation_state_serialize.cc @@ -42,26 +42,18 @@ static std::string escape_name(const StringRef name) return ss.str(); } -static std::string get_blendcache_directory(const Main &bmain) +static std::string get_blend_file_name(const Main &bmain) { - StringRefNull blend_file_path = BKE_main_blendfile_path(&bmain); - char blend_directory[FILE_MAX]; + const StringRefNull blend_file_path = BKE_main_blendfile_path(&bmain); char blend_name[FILE_MAX]; - BLI_path_split_dir_file(blend_file_path.c_str(), - blend_directory, - sizeof(blend_directory), - blend_name, - sizeof(blend_name)); + + BLI_path_split_file_part(blend_file_path.c_str(), blend_name, sizeof(blend_name)); const int64_t type_start_index = StringRef(blend_name).rfind("."); if (type_start_index == StringRef::not_found) { return ""; } blend_name[type_start_index] = '\0'; - const std::string blendcache_name = "blendcache_" + StringRef(blend_name); - - char blendcache_dir[FILE_MAX]; - BLI_path_join(blendcache_dir, sizeof(blendcache_dir), blend_directory, blendcache_name.c_str()); - return blendcache_dir; + return "blendcache_" + StringRef(blend_name); } static std::string get_modifier_sim_name(const Object &object, const ModifierData &md) @@ -71,29 +63,18 @@ static std::string get_modifier_sim_name(const Object &object, const ModifierDat return "sim_" + object_name_escaped + "_" + modifier_name_escaped; } -std::string get_bake_directory(const Main &bmain, const Object &object, const ModifierData &md) +std::string get_default_modifier_bake_directory(const Main &bmain, + const Object &object, + const ModifierData &md) { - char bdata_dir[FILE_MAX]; - BLI_path_join(bdata_dir, - sizeof(bdata_dir), - get_blendcache_directory(bmain).c_str(), + char dir[FILE_MAX]; + /* Make path that's relative to the .blend file. */ + BLI_path_join(dir, + sizeof(dir), + "//", + get_blend_file_name(bmain).c_str(), get_modifier_sim_name(object, md).c_str()); - return bdata_dir; -} - -std::string get_bdata_directory(const Main &bmain, const Object &object, const ModifierData &md) -{ - char bdata_dir[FILE_MAX]; - BLI_path_join( - bdata_dir, sizeof(bdata_dir), get_bake_directory(bmain, object, md).c_str(), "bdata"); - return bdata_dir; -} - -std::string get_meta_directory(const Main &bmain, const Object &object, const ModifierData &md) -{ - char meta_dir[FILE_MAX]; - BLI_path_join(meta_dir, sizeof(meta_dir), get_bake_directory(bmain, object, md).c_str(), "meta"); - return meta_dir; + return dir; } std::shared_ptr BDataSlice::serialize() const diff --git a/source/blender/blenloader/intern/versioning_300.cc b/source/blender/blenloader/intern/versioning_300.cc index b34bee27a6a..ee9b20f9cdf 100644 --- a/source/blender/blenloader/intern/versioning_300.cc +++ b/source/blender/blenloader/intern/versioning_300.cc @@ -67,6 +67,7 @@ #include "BKE_modifier.h" #include "BKE_node.hh" #include "BKE_screen.h" +#include "BKE_simulation_state_serialize.hh" #include "BKE_workspace.h" #include "RNA_access.h" @@ -4483,5 +4484,21 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain) /* Keep this block, even when empty. */ BKE_animdata_main_cb(bmain, version_liboverride_nla_frame_start_end, NULL); + + /* Store simulation bake directory in geometry nodes modifier. */ + LISTBASE_FOREACH (Object *, ob, &bmain->objects) { + LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) { + if (md->type != eModifierType_Nodes) { + continue; + } + NodesModifierData *nmd = reinterpret_cast(md); + if (nmd->simulation_bake_directory) { + continue; + } + const std::string bake_dir = blender::bke::sim::get_default_modifier_bake_directory( + *bmain, *ob, *md); + nmd->simulation_bake_directory = BLI_strdup(bake_dir.c_str()); + } + } } } diff --git a/source/blender/editors/object/object_bake_simulation.cc b/source/blender/editors/object/object_bake_simulation.cc index ef85a05370d..1ae4479e565 100644 --- a/source/blender/editors/object/object_bake_simulation.cc +++ b/source/blender/editors/object/object_bake_simulation.cc @@ -209,8 +209,7 @@ static bool bake_simulation_poll(bContext *C) struct ModifierBakeData { NodesModifierData *nmd; - std::string meta_dir; - std::string bdata_dir; + std::string absolute_bake_dir; std::unique_ptr bdata_sharing; }; @@ -244,6 +243,9 @@ static void bake_simulation_job_startjob(void *customdata, if (!BKE_id_is_editable(job.bmain, &object->id)) { continue; } + + const char *base_path = ID_BLEND_PATH(job.bmain, &object->id); + ObjectBakeData bake_data; bake_data.object = object; LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) { @@ -252,10 +254,14 @@ static void bake_simulation_job_startjob(void *customdata, if (nmd->simulation_cache != nullptr) { nmd->simulation_cache->reset(); } - bake_data.modifiers.append({nmd, - bke::sim::get_meta_directory(*job.bmain, *object, *md), - bke::sim::get_bdata_directory(*job.bmain, *object, *md), - std::make_unique()}); + if (StringRef(nmd->simulation_bake_directory).is_empty()) { + nmd->simulation_bake_directory = BLI_strdup( + bke::sim::get_default_modifier_bake_directory(*job.bmain, *object, *md).c_str()); + } + char absolute_bake_dir[FILE_MAX]; + STRNCPY(absolute_bake_dir, nmd->simulation_bake_directory); + BLI_path_abs(absolute_bake_dir, base_path); + bake_data.modifiers.append({nmd, absolute_bake_dir, std::make_unique()}); } } objects_to_bake.append(std::move(bake_data)); @@ -305,12 +311,14 @@ static void bake_simulation_job_startjob(void *customdata, char bdata_path[FILE_MAX]; BLI_path_join(bdata_path, sizeof(bdata_path), - modifier_bake_data.bdata_dir.c_str(), + modifier_bake_data.absolute_bake_dir.c_str(), + "bdata", bdata_file_name.c_str()); char meta_path[FILE_MAX]; BLI_path_join(meta_path, sizeof(meta_path), - modifier_bake_data.meta_dir.c_str(), + modifier_bake_data.absolute_bake_dir.c_str(), + "meta", meta_file_name.c_str()); BLI_file_ensure_parent_dir_exists(bdata_path); @@ -429,21 +437,25 @@ static int delete_baked_simulation_exec(bContext *C, wmOperator *op) } for (Object *object : objects) { + const char *base_path = ID_BLEND_PATH(bmain, &object->id); LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) { if (md->type == eModifierType_Nodes) { NodesModifierData *nmd = reinterpret_cast(md); - const std::string bake_directory = bke::sim::get_bake_directory(*bmain, *object, *md); - if (BLI_exists(bake_directory.c_str())) { - if (BLI_delete(bake_directory.c_str(), true, true)) { - BKE_reportf(op->reports, - RPT_ERROR, - "Failed to remove bake directory %s", - bake_directory.c_str()); - } - } if (nmd->simulation_cache != nullptr) { nmd->simulation_cache->reset(); } + if (StringRef(nmd->simulation_bake_directory).is_empty()) { + continue; + } + char absolute_bake_dir[FILE_MAX]; + STRNCPY(absolute_bake_dir, nmd->simulation_bake_directory); + BLI_path_abs(absolute_bake_dir, base_path); + if (BLI_exists(absolute_bake_dir)) { + if (BLI_delete(absolute_bake_dir, true, true)) { + BKE_reportf( + op->reports, RPT_ERROR, "Failed to remove bake directory %s", absolute_bake_dir); + } + } } } diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 1fb67802460..880efc4b41d 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -2319,6 +2319,11 @@ typedef struct NodesModifierData { ModifierData modifier; struct bNodeTree *node_group; struct NodesModifierSettings settings; + /** + * Directory where baked simulation states are stored. This may be relative to the .blend file. + */ + char *simulation_bake_directory; + void *_pad; /** * Contains logged information from the last evaluation. diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index 08b9bc3c664..19f9dbace86 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -15,6 +15,7 @@ #include "BLI_listbase.h" #include "BLI_math_vector_types.hh" #include "BLI_multi_value_map.hh" +#include "BLI_path_util.h" #include "BLI_set.hh" #include "BLI_string.h" #include "BLI_string_search.h" @@ -1152,9 +1153,14 @@ static void prepare_simulation_states_for_evaluation(const NodesModifierData &nm if (nmd_orig.simulation_cache->cache_state() != bke::sim::CacheState::Baked && !bmain_path.is_empty()) { - nmd_orig.simulation_cache->try_discover_bake( - bke::sim::get_meta_directory(*bmain, *ctx.object, nmd.modifier), - bke::sim::get_bdata_directory(*bmain, *ctx.object, nmd.modifier)); + if (!StringRef(nmd.simulation_bake_directory).is_empty()) { + if (const char *base_path = ID_BLEND_PATH(bmain, &ctx.object->id)) { + char absolute_bake_dir[FILE_MAX]; + STRNCPY(absolute_bake_dir, nmd.simulation_bake_directory); + BLI_path_abs(absolute_bake_dir, base_path); + nmd_orig.simulation_cache->try_discover_bake(absolute_bake_dir); + } + } } } @@ -1995,6 +2001,8 @@ static void blendWrite(BlendWriter *writer, const ID * /*id_owner*/, const Modif BLO_write_struct(writer, NodesModifierData, nmd); + BLO_write_string(writer, nmd->simulation_bake_directory); + if (nmd->settings.properties != nullptr) { Map boolean_props; if (!BLO_write_is_undo(writer)) { @@ -2033,6 +2041,7 @@ static void blendWrite(BlendWriter *writer, const ID * /*id_owner*/, const Modif static void blendRead(BlendDataReader *reader, ModifierData *md) { NodesModifierData *nmd = reinterpret_cast(md); + BLO_read_data_address(reader, &nmd->simulation_bake_directory); if (nmd->node_group == nullptr) { nmd->settings.properties = nullptr; } @@ -2053,6 +2062,9 @@ static void copyData(const ModifierData *md, ModifierData *target, const int fla tnmd->runtime_eval_log = nullptr; tnmd->simulation_cache = nullptr; + tnmd->simulation_bake_directory = nmd->simulation_bake_directory ? + BLI_strdup(nmd->simulation_bake_directory) : + nullptr; if (nmd->settings.properties != nullptr) { tnmd->settings.properties = IDP_CopyProperty_ex(nmd->settings.properties, flag); @@ -2068,6 +2080,7 @@ static void freeData(ModifierData *md) } MEM_delete(nmd->simulation_cache); + MEM_SAFE_FREE(nmd->simulation_bake_directory); clear_runtime_data(nmd); }