Blender V4.3
bake_geometry_nodes_modifier_pack.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
7#include "BKE_main.hh"
8#include "BKE_packedFile.hh"
9#include "BKE_report.hh"
10
11#include "DNA_modifier_types.h"
12
13#include "MOD_nodes.hh"
14
15#include "BLI_fileops.hh"
16#include "BLI_path_utils.hh"
17#include "BLI_string.h"
18
19#include "DEG_depsgraph.hh"
20
21namespace blender::bke::bake {
22
24 ReportList *reports)
25{
26 if (!BLI_is_dir(directory.c_str())) {
27 BKE_reportf(reports, RPT_ERROR, "%s is no directory", directory.c_str());
28 return {};
29 }
30
31 direntry *dir_entries = nullptr;
32 const int dir_entries_num = BLI_filelist_dir_contents(directory.c_str(), &dir_entries);
33 BLI_SCOPED_DEFER([&]() { BLI_filelist_free(dir_entries, dir_entries_num); });
34
36 for (const int i : IndexRange(dir_entries_num)) {
37 const direntry &dir_entry = dir_entries[i];
38 const StringRefNull dir_entry_path = dir_entry.path;
39 const StringRefNull name = dir_entry.relname;
40 NodesModifierBakeFile bake_file;
41 bake_file.name = BLI_strdup_null(name.c_str());
42 bake_file.packed_file = BKE_packedfile_new(reports, dir_entry_path.c_str(), "");
43 if (bake_file.packed_file) {
44 bake_files.append(bake_file);
45 }
46 }
47
48 return bake_files;
49}
50
52{
54 bake_path.meta_dir, reports);
55 if (meta_bake_files.is_empty()) {
56 return nullptr;
57 }
58
60 bake_path.blobs_dir, reports);
61
62 NodesModifierPackedBake *packed_bake = MEM_cnew<NodesModifierPackedBake>(__func__);
63 packed_bake->meta_files_num = meta_bake_files.size();
64 packed_bake->blob_files_num = blob_bake_files.size();
65
66 packed_bake->meta_files = MEM_cnew_array<NodesModifierBakeFile>(packed_bake->meta_files_num,
67 __func__);
68 packed_bake->blob_files = MEM_cnew_array<NodesModifierBakeFile>(packed_bake->blob_files_num,
69 __func__);
70
71 uninitialized_copy_n(meta_bake_files.data(), meta_bake_files.size(), packed_bake->meta_files);
72 uninitialized_copy_n(blob_bake_files.data(), blob_bake_files.size(), packed_bake->blob_files);
73
74 return packed_bake;
75}
76
78 const BakePath &bake_path,
79 ReportList *reports)
80{
81 auto unpack_file = [&](const StringRefNull directory, const NodesModifierBakeFile &bake_file) {
82 char file_path[FILE_MAX];
83 BLI_path_join(file_path, sizeof(file_path), directory.c_str(), bake_file.name);
84 if (!BLI_file_ensure_parent_dir_exists(file_path)) {
85 BKE_reportf(reports, RPT_ERROR, "Can't ensure directory: %s", directory.c_str());
86 return false;
87 }
88 fstream fs(file_path, std::ios::out);
89 fs.write(static_cast<const char *>(bake_file.packed_file->data), bake_file.packed_file->size);
90 if (fs.bad()) {
91 BKE_reportf(reports, RPT_ERROR, "Can't write file : %s", file_path);
92 return false;
93 }
94 return true;
95 };
96
97 for (const NodesModifierBakeFile &bake_file :
98 Span{packed_bake.meta_files, packed_bake.meta_files_num})
99 {
100 if (!unpack_file(bake_path.meta_dir, bake_file)) {
101 return false;
102 }
103 }
104 for (const NodesModifierBakeFile &bake_file :
105 Span{packed_bake.blob_files, packed_bake.blob_files_num})
106 {
107 if (!unpack_file(bake_path.blobs_dir, bake_file)) {
108 return false;
109 }
110 }
111 return true;
112}
113
115 ReportList *reports,
116 Object &object,
119{
120 if (bake.packed) {
122 }
123 const std::optional<bake::BakePath> bake_path = get_node_bake_path(bmain, object, nmd, bake.id);
124 if (!bake_path) {
126 }
127 bake.packed = bake::pack_bake_from_disk(*bake_path, reports);
128 if (!bake.packed) {
130 }
131 nmd.runtime->cache->reset_cache(bake.id);
135}
136
138{
139 direntry *entries = nullptr;
140 const int entries_num = BLI_filelist_dir_contents(path.c_str(), &entries);
141 BLI_filelist_free(entries, entries_num);
142 return entries_num == 0;
143}
144
146{
147 return !directory_is_empty(path.meta_dir);
148}
149
151 ReportList *reports,
152 Object &object,
155 ePF_FileStatus how)
156{
157 if (!bake.packed) {
159 }
160 if (StringRef(BKE_main_blendfile_path(&bmain)).is_empty()) {
161 BKE_report(reports, RPT_ERROR, "Can only unpack bake if the current .blend file is saved");
163 }
164
166
167 auto prepare_local_path = [&]() {
168 const std::string directory = bake::get_default_node_bake_directory(
169 bmain, object, nmd, bake.id);
171 MEM_SAFE_FREE(bake.directory);
172 bake.directory = BLI_strdup(directory.c_str());
173 const char *base_path = ID_BLEND_PATH(&bmain, &object.id);
174 char absolute_dir[FILE_MAX];
175 STRNCPY(absolute_dir, directory.c_str());
176 BLI_path_abs(absolute_dir, base_path);
177 return bake::BakePath::from_single_root(absolute_dir);
178 };
179 auto prepare_original_path = [&]() {
180 if (const std::optional<bake::BakePath> bake_path = bake::get_node_bake_path(
181 bmain, object, nmd, bake.id))
182 {
183 return *bake_path;
184 }
185 return prepare_local_path();
186 };
187 auto delete_bake_on_disk = [&](const bake::BakePath &bake_path) {
188 BLI_delete(bake_path.meta_dir.c_str(), true, true);
189 BLI_delete(bake_path.blobs_dir.c_str(), true, true);
190 };
191 auto free_packed_bake = [&]() {
193 bake.packed = nullptr;
194 nmd.runtime->cache->reset_cache(bake.id);
195 };
196 auto finalize_on_success = [&]() {
199 };
200
201 switch (how) {
202 case PF_USE_ORIGINAL: {
203 const bake::BakePath bake_path = prepare_original_path();
204 if (!disk_bake_exists(bake_path)) {
205 delete_bake_on_disk(bake_path);
206 if (!bake::unpack_bake_to_disk(*bake.packed, bake_path, reports)) {
208 }
209 }
210 free_packed_bake();
211 return finalize_on_success();
212 }
213 case PF_WRITE_ORIGINAL: {
214 const bake::BakePath bake_path = prepare_original_path();
215 delete_bake_on_disk(bake_path);
216 if (!bake::unpack_bake_to_disk(*bake.packed, bake_path, reports)) {
218 }
219 free_packed_bake();
220 return finalize_on_success();
221 }
222 case PF_USE_LOCAL: {
223 const bake::BakePath bake_path = prepare_local_path();
224 if (!disk_bake_exists(bake_path)) {
225 delete_bake_on_disk(bake_path);
226 if (!bake::unpack_bake_to_disk(*bake.packed, bake_path, reports)) {
228 }
229 }
230 free_packed_bake();
231 return finalize_on_success();
232 }
233 case PF_WRITE_LOCAL: {
234 const bake::BakePath bake_path = prepare_local_path();
235 delete_bake_on_disk(bake_path);
236 if (!bake::unpack_bake_to_disk(*bake.packed, bake_path, reports)) {
238 }
239 free_packed_bake();
240 return finalize_on_success();
241 }
242 case PF_KEEP: {
243 return finalize_on_success();
244 }
245 case PF_REMOVE: {
246 free_packed_bake();
247 return finalize_on_success();
248 }
249 default: {
250 break;
251 }
252 }
254}
255
256} // namespace blender::bke::bake
const char * BKE_main_blendfile_path(const Main *bmain) ATTR_NONNULL()
Definition main.cc:832
PackedFile * BKE_packedfile_new(ReportList *reports, const char *filepath_rel, const char *basepath)
ePF_FileStatus
@ PF_USE_ORIGINAL
@ PF_USE_LOCAL
@ PF_KEEP
@ PF_REMOVE
@ PF_WRITE_ORIGINAL
@ PF_WRITE_LOCAL
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:125
unsigned int BLI_filelist_dir_contents(const char *dirname, struct direntry **r_filelist)
int BLI_delete(const char *path, bool dir, bool recursive) ATTR_NONNULL()
bool BLI_is_dir(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition storage.cc:433
void BLI_filelist_free(struct direntry *filelist, unsigned int nrentries)
bool BLI_file_ensure_parent_dir_exists(const char *filepath) ATTR_NONNULL(1)
Definition fileops_c.cc:429
File and directory operations.
#define BLI_SCOPED_DEFER(function_to_defer)
bool BLI_path_abs(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1
#define FILE_MAX
#define BLI_path_join(...)
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC
Definition string.c:40
#define STRNCPY(dst, src)
Definition BLI_string.h:593
char * BLI_strdup_null(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_MALLOC
Definition string.c:45
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1041
#define ID_BLEND_PATH(_bmain, _id)
Definition DNA_ID.h:647
@ NODES_MODIFIER_BAKE_TARGET_PACKED
@ NODES_MODIFIER_BAKE_TARGET_DISK
@ NODES_MODIFIER_BAKE_CUSTOM_PATH
#define MEM_SAFE_FREE(v)
constexpr const char * c_str() const
int64_t size() const
bool is_empty() const
std::optional< BakePath > get_node_bake_path(const Main &bmain, const Object &object, const NodesModifierData &nmd, int node_id)
bool unpack_bake_to_disk(const NodesModifierPackedBake &packed_bake, const BakePath &bake_path, ReportList *reports)
NodesModifierPackedBake * pack_bake_from_disk(const BakePath &bake_path, ReportList *reports)
UnpackGeometryNodesBakeResult unpack_geometry_nodes_bake(Main &bmain, ReportList *reports, Object &object, NodesModifierData &nmd, NodesModifierBake &bake, ePF_FileStatus how)
static bool directory_is_empty(const blender::StringRefNull path)
PackGeometryNodesBakeResult pack_geometry_nodes_bake(Main &bmain, ReportList *reports, Object &object, NodesModifierData &nmd, NodesModifierBake &bake)
static Vector< NodesModifierBakeFile > pack_files_from_directory(const StringRefNull directory, ReportList *reports)
static bool disk_bake_exists(const blender::bke::bake::BakePath &path)
std::string get_default_node_bake_directory(const Main &bmain, const Object &object, const NodesModifierData &nmd, int node_id)
void nodes_modifier_packed_bake_free(NodesModifierPackedBake *packed_bake)
void uninitialized_copy_n(const T *src, int64_t n, T *dst)
NodesModifierRuntimeHandle * runtime
NodesModifierBakeFile * meta_files
NodesModifierBakeFile * blob_files
static BakePath from_single_root(StringRefNull root_dir)
const char * relname
const char * path