Blender V5.0
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#include "DNA_object_types.h"
14
15#include "MOD_nodes.hh"
16
17#include "BLI_fileops.hh"
18#include "BLI_path_utils.hh"
19#include "BLI_string.h"
20
21#include "DEG_depsgraph.hh"
22
23namespace blender::bke::bake {
24
26 ReportList *reports)
27{
28 if (!BLI_is_dir(directory.c_str())) {
29 BKE_reportf(reports, RPT_ERROR, "%s is not a directory", directory.c_str());
30 return {};
31 }
32
33 direntry *dir_entries = nullptr;
34 const int dir_entries_num = BLI_filelist_dir_contents(directory.c_str(), &dir_entries);
35 BLI_SCOPED_DEFER([&]() { BLI_filelist_free(dir_entries, dir_entries_num); });
36
38 for (const int i : IndexRange(dir_entries_num)) {
39 const direntry &dir_entry = dir_entries[i];
40 const StringRefNull dir_entry_path = dir_entry.path;
41 const StringRefNull name = dir_entry.relname;
42 if (FILENAME_IS_CURRPAR(name.c_str())) {
43 continue;
44 }
45 NodesModifierBakeFile bake_file;
46 bake_file.name = BLI_strdup_null(name.c_str());
47 bake_file.packed_file = BKE_packedfile_new(reports, dir_entry_path.c_str(), "");
48 if (bake_file.packed_file) {
49 bake_files.append(bake_file);
50 }
51 }
52
53 return bake_files;
54}
55
57{
59 bake_path.meta_dir, reports);
60 if (meta_bake_files.is_empty()) {
61 return nullptr;
62 }
63
65 bake_path.blobs_dir, reports);
66
68 packed_bake->meta_files_num = meta_bake_files.size();
69 packed_bake->blob_files_num = blob_bake_files.size();
70
72 __func__);
74 __func__);
75
76 uninitialized_copy_n(meta_bake_files.data(), meta_bake_files.size(), packed_bake->meta_files);
77 uninitialized_copy_n(blob_bake_files.data(), blob_bake_files.size(), packed_bake->blob_files);
78
79 return packed_bake;
80}
81
83 const BakePath &bake_path,
84 ReportList *reports)
85{
86 auto unpack_file = [&](const StringRefNull directory, const NodesModifierBakeFile &bake_file) {
87 char file_path[FILE_MAX];
88 BLI_path_join(file_path, sizeof(file_path), directory.c_str(), bake_file.name);
89 if (!BLI_file_ensure_parent_dir_exists(file_path)) {
90 BKE_reportf(reports, RPT_ERROR, "Cannot ensure directory: %s", directory.c_str());
91 return false;
92 }
93 fstream fs(file_path, std::ios::out | std::ios::binary);
94 fs.write(static_cast<const char *>(bake_file.packed_file->data), bake_file.packed_file->size);
95 if (fs.bad()) {
96 BKE_reportf(reports, RPT_ERROR, "Cannot write file: %s", file_path);
97 return false;
98 }
99 return true;
100 };
101
102 for (const NodesModifierBakeFile &bake_file :
103 Span{packed_bake.meta_files, packed_bake.meta_files_num})
104 {
105 if (!unpack_file(bake_path.meta_dir, bake_file)) {
106 return false;
107 }
108 }
109 for (const NodesModifierBakeFile &bake_file :
110 Span{packed_bake.blob_files, packed_bake.blob_files_num})
111 {
112 if (!unpack_file(bake_path.blobs_dir, bake_file)) {
113 return false;
114 }
115 }
116 return true;
117}
118
120 ReportList *reports,
121 Object &object,
124{
125 if (bake.packed) {
127 }
128 const std::optional<bake::BakePath> bake_path = get_node_bake_path(bmain, object, nmd, bake.id);
129 if (!bake_path) {
131 }
132 bake.packed = bake::pack_bake_from_disk(*bake_path, reports);
133 if (!bake.packed) {
135 }
136 nmd.runtime->cache->reset_cache(bake.id);
140}
141
143{
144 direntry *entries = nullptr;
145 const int entries_num = BLI_filelist_dir_contents(path.c_str(), &entries);
146 BLI_SCOPED_DEFER([&]() { BLI_filelist_free(entries, entries_num); });
147 for (const int i : IndexRange(entries_num)) {
148 const direntry &entry = entries[i];
149 if (FILENAME_IS_CURRPAR(entry.relname)) {
150 continue;
151 }
152 return false;
153 }
154 return true;
155}
156
158{
159 return !directory_is_empty(path.meta_dir);
160}
161
163 ReportList *reports,
164 Object &object,
167 ePF_FileStatus how)
168{
169 if (!bake.packed) {
171 }
172 if (StringRef(BKE_main_blendfile_path(&bmain)).is_empty()) {
173 BKE_report(reports, RPT_ERROR, "Can only unpack bake if the current .blend file is saved");
175 }
176
178
179 auto prepare_local_path = [&]() {
180 const std::string directory = bake::get_default_node_bake_directory(
181 bmain, object, nmd, bake.id);
183 MEM_SAFE_FREE(bake.directory);
184 bake.directory = BLI_strdup(directory.c_str());
185 const char *base_path = ID_BLEND_PATH(&bmain, &object.id);
186 char absolute_dir[FILE_MAX];
187 STRNCPY(absolute_dir, directory.c_str());
188 BLI_path_abs(absolute_dir, base_path);
189 return bake::BakePath::from_single_root(absolute_dir);
190 };
191 auto prepare_original_path = [&]() {
192 if (const std::optional<bake::BakePath> bake_path = bake::get_node_bake_path(
193 bmain, object, nmd, bake.id))
194 {
195 return *bake_path;
196 }
197 return prepare_local_path();
198 };
199 auto delete_bake_on_disk = [&](const bake::BakePath &bake_path) {
200 BLI_delete(bake_path.meta_dir.c_str(), true, true);
201 BLI_delete(bake_path.blobs_dir.c_str(), true, true);
202 };
203 auto free_packed_bake = [&]() {
205 bake.packed = nullptr;
206 nmd.runtime->cache->reset_cache(bake.id);
207 };
208 auto finalize_on_success = [&]() {
211 };
212
213 switch (how) {
214 case PF_USE_ORIGINAL: {
215 const bake::BakePath bake_path = prepare_original_path();
216 if (!disk_bake_exists(bake_path)) {
217 delete_bake_on_disk(bake_path);
218 if (!bake::unpack_bake_to_disk(*bake.packed, bake_path, reports)) {
220 }
221 }
222 free_packed_bake();
223 return finalize_on_success();
224 }
225 case PF_WRITE_ORIGINAL: {
226 const bake::BakePath bake_path = prepare_original_path();
227 delete_bake_on_disk(bake_path);
228 if (!bake::unpack_bake_to_disk(*bake.packed, bake_path, reports)) {
230 }
231 free_packed_bake();
232 return finalize_on_success();
233 }
234 case PF_USE_LOCAL: {
235 const bake::BakePath bake_path = prepare_local_path();
236 if (!disk_bake_exists(bake_path)) {
237 delete_bake_on_disk(bake_path);
238 if (!bake::unpack_bake_to_disk(*bake.packed, bake_path, reports)) {
240 }
241 }
242 free_packed_bake();
243 return finalize_on_success();
244 }
245 case PF_WRITE_LOCAL: {
246 const bake::BakePath bake_path = prepare_local_path();
247 delete_bake_on_disk(bake_path);
248 if (!bake::unpack_bake_to_disk(*bake.packed, bake_path, reports)) {
250 }
251 free_packed_bake();
252 return finalize_on_success();
253 }
254 case PF_KEEP: {
255 return finalize_on_success();
256 }
257 case PF_REMOVE: {
258 free_packed_bake();
259 return finalize_on_success();
260 }
261 default: {
262 break;
263 }
264 }
266}
267
268} // namespace blender::bke::bake
const char * BKE_main_blendfile_path(const Main *bmain) ATTR_NONNULL()
Definition main.cc:887
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
@ RPT_ERROR
Definition BKE_report.hh:39
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:153
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:443
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:452
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:693
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1074
#define ID_BLEND_PATH(_bmain, _id)
Definition DNA_ID.h:685
@ NODES_MODIFIER_BAKE_TARGET_PACKED
@ NODES_MODIFIER_BAKE_TARGET_DISK
@ NODES_MODIFIER_BAKE_CUSTOM_PATH
Object is a sort of wrapper for general info.
#define MEM_SAFE_FREE(v)
constexpr const char * c_str() const
int64_t size() const
bool is_empty() const
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)
const char * name
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