Blender V4.5
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_library.hh"
8#include "BKE_main.hh"
9#include "BKE_packedFile.hh"
10#include "BKE_report.hh"
11
12#include "DNA_modifier_types.h"
13
14#include "MOD_nodes.hh"
15
16#include "BLI_fileops.hh"
17#include "BLI_path_utils.hh"
18#include "BLI_string.h"
19
20#include "DEG_depsgraph.hh"
21
22namespace blender::bke::bake {
23
26{
27 if (!BLI_is_dir(directory.c_str())) {
28 BKE_reportf(reports, RPT_ERROR, "%s is not a directory", directory.c_str());
29 return {};
30 }
31
32 direntry *dir_entries = nullptr;
33 const int dir_entries_num = BLI_filelist_dir_contents(directory.c_str(), &dir_entries);
34 BLI_SCOPED_DEFER([&]() { BLI_filelist_free(dir_entries, dir_entries_num); });
35
37 for (const int i : IndexRange(dir_entries_num)) {
38 const direntry &dir_entry = dir_entries[i];
39 const StringRefNull dir_entry_path = dir_entry.path;
40 const StringRefNull name = dir_entry.relname;
41 if (FILENAME_IS_CURRPAR(name.c_str())) {
42 continue;
43 }
44 NodesModifierBakeFile bake_file;
45 bake_file.name = BLI_strdup_null(name.c_str());
46 bake_file.packed_file = BKE_packedfile_new(reports, dir_entry_path.c_str(), "");
47 if (bake_file.packed_file) {
48 bake_files.append(bake_file);
49 }
50 }
51
52 return bake_files;
53}
54
56{
58 bake_path.meta_dir, reports);
59 if (meta_bake_files.is_empty()) {
60 return nullptr;
61 }
62
64 bake_path.blobs_dir, reports);
65
67 packed_bake->meta_files_num = meta_bake_files.size();
68 packed_bake->blob_files_num = blob_bake_files.size();
69
71 __func__);
73 __func__);
74
75 uninitialized_copy_n(meta_bake_files.data(), meta_bake_files.size(), packed_bake->meta_files);
76 uninitialized_copy_n(blob_bake_files.data(), blob_bake_files.size(), packed_bake->blob_files);
77
78 return packed_bake;
79}
80
82 const BakePath &bake_path,
84{
85 auto unpack_file = [&](const StringRefNull directory, const NodesModifierBakeFile &bake_file) {
86 char file_path[FILE_MAX];
87 BLI_path_join(file_path, sizeof(file_path), directory.c_str(), bake_file.name);
88 if (!BLI_file_ensure_parent_dir_exists(file_path)) {
89 BKE_reportf(reports, RPT_ERROR, "Cannot ensure directory: %s", directory.c_str());
90 return false;
91 }
92 fstream fs(file_path, std::ios::out | std::ios::binary);
93 fs.write(static_cast<const char *>(bake_file.packed_file->data), bake_file.packed_file->size);
94 if (fs.bad()) {
95 BKE_reportf(reports, RPT_ERROR, "Cannot write file: %s", file_path);
96 return false;
97 }
98 return true;
99 };
100
101 for (const NodesModifierBakeFile &bake_file :
102 Span{packed_bake.meta_files, packed_bake.meta_files_num})
103 {
104 if (!unpack_file(bake_path.meta_dir, bake_file)) {
105 return false;
106 }
107 }
108 for (const NodesModifierBakeFile &bake_file :
109 Span{packed_bake.blob_files, packed_bake.blob_files_num})
110 {
111 if (!unpack_file(bake_path.blobs_dir, bake_file)) {
112 return false;
113 }
114 }
115 return true;
116}
117
120 Object &object,
123{
124 if (bake.packed) {
126 }
127 const std::optional<bake::BakePath> bake_path = get_node_bake_path(bmain, object, nmd, bake.id);
128 if (!bake_path) {
130 }
131 bake.packed = bake::pack_bake_from_disk(*bake_path, reports);
132 if (!bake.packed) {
134 }
135 nmd.runtime->cache->reset_cache(bake.id);
139}
140
142{
143 direntry *entries = nullptr;
144 const int entries_num = BLI_filelist_dir_contents(path.c_str(), &entries);
145 BLI_SCOPED_DEFER([&]() { BLI_filelist_free(entries, entries_num); });
146 for (const int i : IndexRange(entries_num)) {
147 const direntry &entry = entries[i];
148 if (FILENAME_IS_CURRPAR(entry.relname)) {
149 continue;
150 }
151 return false;
152 }
153 return true;
154}
155
157{
158 return !directory_is_empty(path.meta_dir);
159}
160
163 Object &object,
166 ePF_FileStatus how)
167{
168 if (!bake.packed) {
170 }
171 if (StringRef(BKE_main_blendfile_path(&bmain)).is_empty()) {
172 BKE_report(reports, RPT_ERROR, "Can only unpack bake if the current .blend file is saved");
174 }
175
177
178 auto prepare_local_path = [&]() {
179 const std::string directory = bake::get_default_node_bake_directory(
180 bmain, object, nmd, bake.id);
182 MEM_SAFE_FREE(bake.directory);
183 bake.directory = BLI_strdup(directory.c_str());
184 const char *base_path = ID_BLEND_PATH(&bmain, &object.id);
185 char absolute_dir[FILE_MAX];
186 STRNCPY(absolute_dir, directory.c_str());
187 BLI_path_abs(absolute_dir, base_path);
188 return bake::BakePath::from_single_root(absolute_dir);
189 };
190 auto prepare_original_path = [&]() {
191 if (const std::optional<bake::BakePath> bake_path = bake::get_node_bake_path(
192 bmain, object, nmd, bake.id))
193 {
194 return *bake_path;
195 }
196 return prepare_local_path();
197 };
198 auto delete_bake_on_disk = [&](const bake::BakePath &bake_path) {
199 BLI_delete(bake_path.meta_dir.c_str(), true, true);
200 BLI_delete(bake_path.blobs_dir.c_str(), true, true);
201 };
202 auto free_packed_bake = [&]() {
204 bake.packed = nullptr;
205 nmd.runtime->cache->reset_cache(bake.id);
206 };
207 auto finalize_on_success = [&]() {
210 };
211
212 switch (how) {
213 case PF_USE_ORIGINAL: {
214 const bake::BakePath bake_path = prepare_original_path();
215 if (!disk_bake_exists(bake_path)) {
216 delete_bake_on_disk(bake_path);
217 if (!bake::unpack_bake_to_disk(*bake.packed, bake_path, reports)) {
219 }
220 }
221 free_packed_bake();
222 return finalize_on_success();
223 }
224 case PF_WRITE_ORIGINAL: {
225 const bake::BakePath bake_path = prepare_original_path();
226 delete_bake_on_disk(bake_path);
227 if (!bake::unpack_bake_to_disk(*bake.packed, bake_path, reports)) {
229 }
230 free_packed_bake();
231 return finalize_on_success();
232 }
233 case PF_USE_LOCAL: {
234 const bake::BakePath bake_path = prepare_local_path();
235 if (!disk_bake_exists(bake_path)) {
236 delete_bake_on_disk(bake_path);
237 if (!bake::unpack_bake_to_disk(*bake.packed, bake_path, reports)) {
239 }
240 }
241 free_packed_bake();
242 return finalize_on_success();
243 }
244 case PF_WRITE_LOCAL: {
245 const bake::BakePath bake_path = prepare_local_path();
246 delete_bake_on_disk(bake_path);
247 if (!bake::unpack_bake_to_disk(*bake.packed, bake_path, reports)) {
249 }
250 free_packed_bake();
251 return finalize_on_success();
252 }
253 case PF_KEEP: {
254 return finalize_on_success();
255 }
256 case PF_REMOVE: {
257 free_packed_bake();
258 return finalize_on_success();
259 }
260 default: {
261 break;
262 }
263 }
265}
266
267} // namespace blender::bke::bake
const char * BKE_main_blendfile_path(const Main *bmain) ATTR_NONNULL()
Definition main.cc:877
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:126
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:456
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(...)
#define FILENAME_IS_CURRPAR(_n)
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC
Definition string.cc:41
char * BLI_strdup_null(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_MALLOC
Definition string.cc:46
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:982
@ NODES_MODIFIER_BAKE_TARGET_PACKED
@ NODES_MODIFIER_BAKE_TARGET_DISK
@ NODES_MODIFIER_BAKE_CUSTOM_PATH
ReportList * reports
Definition WM_types.hh:1025
constexpr const char * c_str() const
int64_t size() const
bool is_empty() const
#define MEM_SAFE_FREE(v)
#define ID_BLEND_PATH(_bmain, _id)
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
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
i
Definition text_draw.cc:230