- "Export additional animationsThis feature..." -> Add period and
newline to separate sentences.
- "name from laoded image" -> "Name from loaded image": typo.
- "Duplicate Active Keyframe (All Layer)" -> "All Layers": grammar.
- "%s is no directory" -> "%s is not a directory": grammar.
- "Can't ensure directory: %s" -> "Cannot", see HIG.
- "Duplicate active Frame(s)": title case.
- "Delete active keyframes of all layer" -> "... layers": grammar.
- "Grease Pencil group color tag": title case.
- "color tag": title case.
- "Bake all line art modifiers" -> "... Line Art...": title case for
product name
- "... imported USD files.Export remaining..." -> "... imported USD
files.\nExport remaining...": missing newline.
- "Premanently delete brush. This can't be undo." -> "Permanently
delete brush. This cannot be undone.": typos.
- "Samplerate" -> "Sample Rate": use more correct two-word form.
- Decimate Keyframe operator: rename and rephrase a property to better
reflect what it does.
- "Remove" -> "Factor"
- "The ratio of remaining keyframes after the operation" ->
"The ratio of keyframes to remove"
- "Add a repository referencing an remote repository" -> "an": typo.
- "... unique within the Action.This is used..." -> "... unique within
the Action.\nThis is used...": missing newline.
- "Threashold in screen space ... within this threashold " ->
"Threshold in screen space ... within this threshold ": typo
- "... occluded by other faces (Slower performance)" -> ... (slower
performance): no need for the capital here.
- "Indices must be sorted in acending order" -> "ascending": typo.
- "Enable the new Overlay code-base" -> "codebase": typo.
- "dectected by plane tracks" -> "detected": typo.
- "the same index can occure" -> "occur": typo.
- "Single element geometry..." -> "Single-element": spelling.
- "it can be quite inefficient to splitup large geometries" -> "split
up": spelling.
- "If true, true gizmo is displayed..." -> "the gizmo": typo.
Some issues reported by Tamuna Mebonia.
Pull Request: https://projects.blender.org/blender/blender/pulls/129001
257 lines
8.9 KiB
C++
257 lines
8.9 KiB
C++
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
#include "BKE_bake_geometry_nodes_modifier.hh"
|
|
#include "BKE_bake_geometry_nodes_modifier_pack.hh"
|
|
#include "BKE_main.hh"
|
|
#include "BKE_packedFile.hh"
|
|
#include "BKE_report.hh"
|
|
|
|
#include "DNA_modifier_types.h"
|
|
|
|
#include "MOD_nodes.hh"
|
|
|
|
#include "BLI_fileops.hh"
|
|
#include "BLI_path_utils.hh"
|
|
#include "BLI_string.h"
|
|
|
|
#include "DEG_depsgraph.hh"
|
|
|
|
namespace blender::bke::bake {
|
|
|
|
static Vector<NodesModifierBakeFile> pack_files_from_directory(const StringRefNull directory,
|
|
ReportList *reports)
|
|
{
|
|
if (!BLI_is_dir(directory.c_str())) {
|
|
BKE_reportf(reports, RPT_ERROR, "%s is not a directory", directory.c_str());
|
|
return {};
|
|
}
|
|
|
|
direntry *dir_entries = nullptr;
|
|
const int dir_entries_num = BLI_filelist_dir_contents(directory.c_str(), &dir_entries);
|
|
BLI_SCOPED_DEFER([&]() { BLI_filelist_free(dir_entries, dir_entries_num); });
|
|
|
|
Vector<NodesModifierBakeFile> bake_files;
|
|
for (const int i : IndexRange(dir_entries_num)) {
|
|
const direntry &dir_entry = dir_entries[i];
|
|
const StringRefNull dir_entry_path = dir_entry.path;
|
|
const StringRefNull name = dir_entry.relname;
|
|
NodesModifierBakeFile bake_file;
|
|
bake_file.name = BLI_strdup_null(name.c_str());
|
|
bake_file.packed_file = BKE_packedfile_new(reports, dir_entry_path.c_str(), "");
|
|
if (bake_file.packed_file) {
|
|
bake_files.append(bake_file);
|
|
}
|
|
}
|
|
|
|
return bake_files;
|
|
}
|
|
|
|
NodesModifierPackedBake *pack_bake_from_disk(const BakePath &bake_path, ReportList *reports)
|
|
{
|
|
const Vector<NodesModifierBakeFile> meta_bake_files = pack_files_from_directory(
|
|
bake_path.meta_dir, reports);
|
|
if (meta_bake_files.is_empty()) {
|
|
return nullptr;
|
|
}
|
|
|
|
const Vector<NodesModifierBakeFile> blob_bake_files = pack_files_from_directory(
|
|
bake_path.blobs_dir, reports);
|
|
|
|
NodesModifierPackedBake *packed_bake = MEM_cnew<NodesModifierPackedBake>(__func__);
|
|
packed_bake->meta_files_num = meta_bake_files.size();
|
|
packed_bake->blob_files_num = blob_bake_files.size();
|
|
|
|
packed_bake->meta_files = MEM_cnew_array<NodesModifierBakeFile>(packed_bake->meta_files_num,
|
|
__func__);
|
|
packed_bake->blob_files = MEM_cnew_array<NodesModifierBakeFile>(packed_bake->blob_files_num,
|
|
__func__);
|
|
|
|
uninitialized_copy_n(meta_bake_files.data(), meta_bake_files.size(), packed_bake->meta_files);
|
|
uninitialized_copy_n(blob_bake_files.data(), blob_bake_files.size(), packed_bake->blob_files);
|
|
|
|
return packed_bake;
|
|
}
|
|
|
|
bool unpack_bake_to_disk(const NodesModifierPackedBake &packed_bake,
|
|
const BakePath &bake_path,
|
|
ReportList *reports)
|
|
{
|
|
auto unpack_file = [&](const StringRefNull directory, const NodesModifierBakeFile &bake_file) {
|
|
char file_path[FILE_MAX];
|
|
BLI_path_join(file_path, sizeof(file_path), directory.c_str(), bake_file.name);
|
|
if (!BLI_file_ensure_parent_dir_exists(file_path)) {
|
|
BKE_reportf(reports, RPT_ERROR, "Cannot ensure directory: %s", directory.c_str());
|
|
return false;
|
|
}
|
|
fstream fs(file_path, std::ios::out);
|
|
fs.write(static_cast<const char *>(bake_file.packed_file->data), bake_file.packed_file->size);
|
|
if (fs.bad()) {
|
|
BKE_reportf(reports, RPT_ERROR, "Cannot write file: %s", file_path);
|
|
return false;
|
|
}
|
|
return true;
|
|
};
|
|
|
|
for (const NodesModifierBakeFile &bake_file :
|
|
Span{packed_bake.meta_files, packed_bake.meta_files_num})
|
|
{
|
|
if (!unpack_file(bake_path.meta_dir, bake_file)) {
|
|
return false;
|
|
}
|
|
}
|
|
for (const NodesModifierBakeFile &bake_file :
|
|
Span{packed_bake.blob_files, packed_bake.blob_files_num})
|
|
{
|
|
if (!unpack_file(bake_path.blobs_dir, bake_file)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
PackGeometryNodesBakeResult pack_geometry_nodes_bake(Main &bmain,
|
|
ReportList *reports,
|
|
Object &object,
|
|
NodesModifierData &nmd,
|
|
NodesModifierBake &bake)
|
|
{
|
|
if (bake.packed) {
|
|
return PackGeometryNodesBakeResult::PackedAlready;
|
|
}
|
|
const std::optional<bake::BakePath> bake_path = get_node_bake_path(bmain, object, nmd, bake.id);
|
|
if (!bake_path) {
|
|
return PackGeometryNodesBakeResult::NoDataFound;
|
|
}
|
|
bake.packed = bake::pack_bake_from_disk(*bake_path, reports);
|
|
if (!bake.packed) {
|
|
return PackGeometryNodesBakeResult::NoDataFound;
|
|
}
|
|
nmd.runtime->cache->reset_cache(bake.id);
|
|
bake.bake_target = NODES_MODIFIER_BAKE_TARGET_PACKED;
|
|
DEG_id_tag_update(&object.id, ID_RECALC_GEOMETRY);
|
|
return PackGeometryNodesBakeResult::Success;
|
|
}
|
|
|
|
static bool directory_is_empty(const blender::StringRefNull path)
|
|
{
|
|
direntry *entries = nullptr;
|
|
const int entries_num = BLI_filelist_dir_contents(path.c_str(), &entries);
|
|
BLI_filelist_free(entries, entries_num);
|
|
return entries_num == 0;
|
|
}
|
|
|
|
static bool disk_bake_exists(const blender::bke::bake::BakePath &path)
|
|
{
|
|
return !directory_is_empty(path.meta_dir);
|
|
}
|
|
|
|
UnpackGeometryNodesBakeResult unpack_geometry_nodes_bake(Main &bmain,
|
|
ReportList *reports,
|
|
Object &object,
|
|
NodesModifierData &nmd,
|
|
NodesModifierBake &bake,
|
|
ePF_FileStatus how)
|
|
{
|
|
if (!bake.packed) {
|
|
return UnpackGeometryNodesBakeResult::NoPackedData;
|
|
}
|
|
if (StringRef(BKE_main_blendfile_path(&bmain)).is_empty()) {
|
|
BKE_report(reports, RPT_ERROR, "Can only unpack bake if the current .blend file is saved");
|
|
return UnpackGeometryNodesBakeResult::BlendFileNotSaved;
|
|
}
|
|
|
|
DEG_id_tag_update(&object.id, ID_RECALC_GEOMETRY);
|
|
|
|
auto prepare_local_path = [&]() {
|
|
const std::string directory = bake::get_default_node_bake_directory(
|
|
bmain, object, nmd, bake.id);
|
|
bake.flag |= NODES_MODIFIER_BAKE_CUSTOM_PATH;
|
|
MEM_SAFE_FREE(bake.directory);
|
|
bake.directory = BLI_strdup(directory.c_str());
|
|
const char *base_path = ID_BLEND_PATH(&bmain, &object.id);
|
|
char absolute_dir[FILE_MAX];
|
|
STRNCPY(absolute_dir, directory.c_str());
|
|
BLI_path_abs(absolute_dir, base_path);
|
|
return bake::BakePath::from_single_root(absolute_dir);
|
|
};
|
|
auto prepare_original_path = [&]() {
|
|
if (const std::optional<bake::BakePath> bake_path = bake::get_node_bake_path(
|
|
bmain, object, nmd, bake.id))
|
|
{
|
|
return *bake_path;
|
|
}
|
|
return prepare_local_path();
|
|
};
|
|
auto delete_bake_on_disk = [&](const bake::BakePath &bake_path) {
|
|
BLI_delete(bake_path.meta_dir.c_str(), true, true);
|
|
BLI_delete(bake_path.blobs_dir.c_str(), true, true);
|
|
};
|
|
auto free_packed_bake = [&]() {
|
|
blender::nodes_modifier_packed_bake_free(bake.packed);
|
|
bake.packed = nullptr;
|
|
nmd.runtime->cache->reset_cache(bake.id);
|
|
};
|
|
auto finalize_on_success = [&]() {
|
|
bake.bake_target = NODES_MODIFIER_BAKE_TARGET_DISK;
|
|
return UnpackGeometryNodesBakeResult::Success;
|
|
};
|
|
|
|
switch (how) {
|
|
case PF_USE_ORIGINAL: {
|
|
const bake::BakePath bake_path = prepare_original_path();
|
|
if (!disk_bake_exists(bake_path)) {
|
|
delete_bake_on_disk(bake_path);
|
|
if (!bake::unpack_bake_to_disk(*bake.packed, bake_path, reports)) {
|
|
return UnpackGeometryNodesBakeResult::Error;
|
|
}
|
|
}
|
|
free_packed_bake();
|
|
return finalize_on_success();
|
|
}
|
|
case PF_WRITE_ORIGINAL: {
|
|
const bake::BakePath bake_path = prepare_original_path();
|
|
delete_bake_on_disk(bake_path);
|
|
if (!bake::unpack_bake_to_disk(*bake.packed, bake_path, reports)) {
|
|
return UnpackGeometryNodesBakeResult::Error;
|
|
}
|
|
free_packed_bake();
|
|
return finalize_on_success();
|
|
}
|
|
case PF_USE_LOCAL: {
|
|
const bake::BakePath bake_path = prepare_local_path();
|
|
if (!disk_bake_exists(bake_path)) {
|
|
delete_bake_on_disk(bake_path);
|
|
if (!bake::unpack_bake_to_disk(*bake.packed, bake_path, reports)) {
|
|
return UnpackGeometryNodesBakeResult::Error;
|
|
}
|
|
}
|
|
free_packed_bake();
|
|
return finalize_on_success();
|
|
}
|
|
case PF_WRITE_LOCAL: {
|
|
const bake::BakePath bake_path = prepare_local_path();
|
|
delete_bake_on_disk(bake_path);
|
|
if (!bake::unpack_bake_to_disk(*bake.packed, bake_path, reports)) {
|
|
return UnpackGeometryNodesBakeResult::Error;
|
|
}
|
|
free_packed_bake();
|
|
return finalize_on_success();
|
|
}
|
|
case PF_KEEP: {
|
|
return finalize_on_success();
|
|
}
|
|
case PF_REMOVE: {
|
|
free_packed_bake();
|
|
return finalize_on_success();
|
|
}
|
|
default: {
|
|
break;
|
|
}
|
|
}
|
|
return UnpackGeometryNodesBakeResult::Error;
|
|
}
|
|
|
|
} // namespace blender::bke::bake
|