Merge branch 'blender-v4.3-release'

This commit is contained in:
Bastien Montagne
2024-11-13 15:34:26 +01:00
8 changed files with 150 additions and 68 deletions

View File

@@ -12,6 +12,8 @@
#include "BLI_rect.h"
#include <optional>
struct Depsgraph;
struct GPUTexture;
struct ID;
@@ -22,6 +24,7 @@ struct ImageFormatData;
struct ImagePool;
struct ImageTile;
struct ImbFormatOptions;
struct Library;
struct ListBase;
struct Main;
struct Object;
@@ -192,16 +195,30 @@ void BKE_image_alpha_mode_from_extension(Image *image);
/**
* Returns a new image or NULL if it can't load.
*
* \note: The `_in_lib` version allows to add a new image in a given library. It also affects the
* root path used for relative filepaths. See also #BKE_id_new and #BKE_id_new_in_lib
* documentation for more details.
*/
Image *BKE_image_load(Main *bmain, const char *filepath);
Image *BKE_image_load_in_lib(Main *bmain,
std::optional<Library *> owner_library,
const char *filepath);
/**
* Returns existing Image when filename/type is same.
*
* Checks if image was already loaded, then returns same image otherwise creates new
* (does not load ibuf itself).
*
* \note: The `_in_lib` version allows to find an existing (or add a new) image in a given library.
* It also affects the root path used for relative filepaths. See also #BKE_id_new and
* #BKE_id_new_in_lib documentation for more details.
*/
Image *BKE_image_load_exists_ex(Main *bmain, const char *filepath, bool *r_exists);
Image *BKE_image_load_exists(Main *bmain, const char *filepath);
Image *BKE_image_load_exists(Main *bmain, const char *filepath, bool *r_exists = nullptr);
Image *BKE_image_load_exists_in_lib(Main *bmain,
std::optional<Library *> owner_library,
const char *filepath,
bool *r_exists = nullptr);
/**
* Adds new image block, creates ImBuf and initializes color.

View File

@@ -691,11 +691,15 @@ static void image_init(Image *ima, short source, short type)
ima->stereo3d_format = MEM_cnew<Stereo3dFormat>("Image Stereo Format");
}
static Image *image_alloc(Main *bmain, const char *name, short source, short type)
static Image *image_alloc(Main *bmain,
std::optional<Library *> owner_library,
const char *name,
short source,
short type)
{
Image *ima;
ima = static_cast<Image *>(BKE_libblock_alloc(bmain, ID_IM, name, 0));
ima = static_cast<Image *>(BKE_libblock_alloc_in_lib(bmain, owner_library, ID_IM, name, 0));
if (ima) {
image_init(ima, source, type);
}
@@ -1032,14 +1036,37 @@ void BKE_image_alpha_mode_from_extension(Image *image)
image->alpha_mode = BKE_image_alpha_mode_from_extension_ex(image->filepath);
}
static void image_abs_path(Main *bmain,
Library *owner_library,
const char *filepath,
char *r_filepath_abs)
{
BLI_strncpy(r_filepath_abs, filepath, FILE_MAX);
if (owner_library) {
BLI_path_abs(r_filepath_abs, owner_library->runtime.filepath_abs);
}
else {
BLI_path_abs(r_filepath_abs, BKE_main_blendfile_path(bmain));
}
}
Image *BKE_image_load(Main *bmain, const char *filepath)
{
return BKE_image_load_in_lib(bmain, std::nullopt, filepath);
}
Image *BKE_image_load_in_lib(Main *bmain,
std::optional<Library *> owner_library,
const char *filepath)
{
Image *ima;
int file;
char filepath_abs[FILE_MAX];
STRNCPY(filepath_abs, filepath);
BLI_path_abs(filepath_abs, BKE_main_blendfile_path(bmain));
/* If no owner library is explicitely given, use the current library from the given Main. */
Library *owner_lib = owner_library.value_or(bmain->curlib);
image_abs_path(bmain, owner_lib, filepath, filepath_abs);
/* exists? */
file = BLI_open(filepath_abs, O_BINARY | O_RDONLY, 0);
@@ -1052,7 +1079,8 @@ Image *BKE_image_load(Main *bmain, const char *filepath)
close(file);
}
ima = image_alloc(bmain, BLI_path_basename(filepath), IMA_SRC_FILE, IMA_TYPE_IMAGE);
ima = image_alloc(
bmain, owner_library, BLI_path_basename(filepath), IMA_SRC_FILE, IMA_TYPE_IMAGE);
STRNCPY(ima->filepath, filepath);
if (BLI_path_extension_check_array(filepath, imb_ext_movie)) {
@@ -1064,13 +1092,23 @@ Image *BKE_image_load(Main *bmain, const char *filepath)
return ima;
}
Image *BKE_image_load_exists_ex(Main *bmain, const char *filepath, bool *r_exists)
Image *BKE_image_load_exists(Main *bmain, const char *filepath, bool *r_exists)
{
return BKE_image_load_exists_in_lib(bmain, std::nullopt, filepath, r_exists);
}
Image *BKE_image_load_exists_in_lib(Main *bmain,
std::optional<Library *> owner_library,
const char *filepath,
bool *r_exists)
{
Image *ima;
char filepath_abs[FILE_MAX], filepath_test[FILE_MAX];
STRNCPY(filepath_abs, filepath);
BLI_path_abs(filepath_abs, bmain->filepath);
/* If not owner library is explicitely given, use the current library from the given Main. */
Library *owner_lib = owner_library.value_or(bmain->curlib);
image_abs_path(bmain, owner_lib, filepath, filepath_abs);
/* first search an identical filepath */
for (ima = static_cast<Image *>(bmain->images.first); ima;
@@ -1080,27 +1118,30 @@ Image *BKE_image_load_exists_ex(Main *bmain, const char *filepath, bool *r_exist
STRNCPY(filepath_test, ima->filepath);
BLI_path_abs(filepath_test, ID_BLEND_PATH(bmain, &ima->id));
if (BLI_path_cmp(filepath_test, filepath_abs) == 0) {
if ((BKE_image_has_anim(ima) == false) || (ima->id.us == 0)) {
id_us_plus(&ima->id); /* officially should not, it doesn't link here! */
if (r_exists) {
*r_exists = true;
}
return ima;
}
if (BLI_path_cmp(filepath_test, filepath_abs) != 0) {
continue;
}
if ((BKE_image_has_anim(ima)) && (ima->id.us != 0)) {
/* TODO explain why animated images with already one or more users are skipped? */
continue;
}
if (ima->id.lib != owner_lib) {
continue;
}
/* FIXME Should not happen here. Only code actually adding an ID usage should increment this
* counter. */
id_us_plus(&ima->id);
if (r_exists) {
*r_exists = true;
}
return ima;
}
}
if (r_exists) {
*r_exists = false;
}
return BKE_image_load(bmain, filepath);
}
Image *BKE_image_load_exists(Main *bmain, const char *filepath)
{
return BKE_image_load_exists_ex(bmain, filepath, nullptr);
return BKE_image_load_in_lib(bmain, owner_library, filepath);
}
struct ImageFillData {
@@ -1225,10 +1266,10 @@ Image *BKE_image_add_generated(Main *bmain,
/* Saving the image changes it's #Image.source to #IMA_SRC_FILE (leave as generated here). */
Image *ima;
if (tiled) {
ima = image_alloc(bmain, name, IMA_SRC_TILED, IMA_TYPE_IMAGE);
ima = image_alloc(bmain, std::nullopt, name, IMA_SRC_TILED, IMA_TYPE_IMAGE);
}
else {
ima = image_alloc(bmain, name, IMA_SRC_GENERATED, IMA_TYPE_UV_TEST);
ima = image_alloc(bmain, std::nullopt, name, IMA_SRC_GENERATED, IMA_TYPE_UV_TEST);
}
if (ima == nullptr) {
return nullptr;
@@ -1312,7 +1353,7 @@ Image *BKE_image_add_from_imbuf(Main *bmain, ImBuf *ibuf, const char *name)
* Otherwise create "generated" image, avoiding invalid configuration with an empty file path. */
const eImageSource source = ibuf->filepath[0] != '\0' ? IMA_SRC_FILE : IMA_SRC_GENERATED;
Image *ima = image_alloc(bmain, name, source, IMA_TYPE_IMAGE);
Image *ima = image_alloc(bmain, std::nullopt, name, source, IMA_TYPE_IMAGE);
if (!ima) {
return nullptr;
@@ -2744,7 +2785,7 @@ Image *BKE_image_ensure_viewer(Main *bmain, int type, const char *name)
}
if (ima == nullptr) {
ima = image_alloc(bmain, name, IMA_SRC_VIEWER, type);
ima = image_alloc(bmain, std::nullopt, name, IMA_SRC_VIEWER, type);
}
/* Happens on reload, image-window cannot be image user when hidden. */

View File

@@ -46,8 +46,18 @@ using AssetListIterFn = FunctionRef<bool(asset_system::AssetRepresentation &)>;
/**
* \warning Never keep the asset handle passed to \a fn outside of \a fn's scope. While iterating,
* the file data wrapped by the asset handle can be freed, since the file cache has a maximum size.
* \note It is recommended to prefilter assets using \a prefilter_fn, which avoids populating the
* file cache with files that will not end up being relevant. With 1000s of assets that can make a
* difference, since often only a small subset needs to be displayed.
*/
void iterate(const AssetLibraryReference &library_reference,
AssetListHandleIterFn fn,
FunctionRef<bool(asset_system::AssetRepresentation &)> prefilter_fn = nullptr);
/**
* \note This override avoids the file caching system, so it's more performant and avoids pitfals
* from the other override. Prefer this when access to #AssetRepresentation is enough, and no
* #AssetHandle is needed.
*/
void iterate(const AssetLibraryReference &library_reference, AssetListHandleIterFn fn);
void iterate(const AssetLibraryReference &library_reference, AssetListIterFn fn);
/**

View File

@@ -123,7 +123,8 @@ class AssetList : NonCopyable {
bool is_loaded() const;
bool is_asset_preview_loading(const AssetHandle &asset) const;
asset_system::AssetLibrary *asset_library() const;
void iterate(AssetListHandleIterFn fn) const;
void iterate(AssetListHandleIterFn fn,
FunctionRef<bool(asset_system::AssetRepresentation &)> prefilter_fn) const;
void iterate(AssetListIterFn fn) const;
int size() const;
void tag_main_data_dirty() const;
@@ -204,17 +205,24 @@ asset_system::AssetLibrary *AssetList::asset_library() const
return reinterpret_cast<asset_system::AssetLibrary *>(filelist_asset_library(filelist_));
}
void AssetList::iterate(AssetListHandleIterFn fn) const
void AssetList::iterate(AssetListHandleIterFn fn,
FunctionRef<bool(asset_system::AssetRepresentation &)> prefilter_fn) const
{
FileList *files = filelist_;
int numfiles = filelist_files_ensure(files);
for (int i = 0; i < numfiles; i++) {
FileDirEntry *file = filelist_file(files, i);
if ((file->typeflag & FILE_TYPE_ASSET) == 0) {
asset_system::AssetRepresentation *asset = filelist_entry_get_asset_representation(files, i);
if (!asset) {
continue;
}
if (prefilter_fn && !prefilter_fn(*asset)) {
continue;
}
FileDirEntry *file = filelist_file(files, i);
AssetHandle asset_handle = {file};
if (!fn(asset_handle)) {
/* If the callback returns false, we stop iterating. */
@@ -495,11 +503,13 @@ bool storage_has_list_for_library(const AssetLibraryReference *library_reference
return lookup_list(*library_reference) != nullptr;
}
void iterate(const AssetLibraryReference &library_reference, AssetListHandleIterFn fn)
void iterate(const AssetLibraryReference &library_reference,
AssetListHandleIterFn fn,
FunctionRef<bool(asset_system::AssetRepresentation &)> prefilter_fn)
{
AssetList *list = lookup_list(library_reference);
if (list) {
list->iterate(fn);
list->iterate(fn, prefilter_fn);
}
}

View File

@@ -104,41 +104,45 @@ void AssetView::build_items()
return;
}
list::iterate(library_ref_, [&](AssetHandle asset_handle) {
const asset_system::AssetRepresentation *asset = handle_get_representation(&asset_handle);
list::iterate(
library_ref_,
[&](AssetHandle asset_handle) {
const asset_system::AssetRepresentation *asset = handle_get_representation(&asset_handle);
const bool show_names = (shelf_.settings.display_flag & ASSETSHELF_SHOW_NAMES);
if (shelf_.type->asset_poll && !shelf_.type->asset_poll(shelf_.type, asset)) {
return true;
}
const StringRef identifier = asset->library_relative_identifier();
const int preview_id = [&]() -> int {
if (list::asset_image_is_loading(&library_ref_, &asset_handle)) {
return ICON_TEMP;
}
return handle_get_preview_or_type_icon_id(&asset_handle);
}();
const AssetMetaData &asset_data = asset->get_metadata();
AssetViewItem &item = this->add_item<AssetViewItem>(
asset_handle, identifier, asset->get_name(), preview_id);
if (!show_names) {
item.hide_label();
}
if (shelf_.type->flag & ASSET_SHELF_TYPE_FLAG_NO_ASSET_DRAG) {
item.disable_asset_drag();
}
if (catalog_filter_ && !catalog_filter_->contains(asset_data.catalog_id)) {
/* Skip this asset. */
return true;
}
return true;
},
const bool show_names = (shelf_.settings.display_flag & ASSETSHELF_SHOW_NAMES);
/* prefilter_fn=*/
[&](asset_system::AssetRepresentation &asset) {
if (shelf_.type->asset_poll && !shelf_.type->asset_poll(shelf_.type, &asset)) {
return false;
}
const StringRef identifier = asset->library_relative_identifier();
const int preview_id = [&]() -> int {
if (list::asset_image_is_loading(&library_ref_, &asset_handle)) {
return ICON_TEMP;
}
return handle_get_preview_or_type_icon_id(&asset_handle);
}();
AssetViewItem &item = this->add_item<AssetViewItem>(
asset_handle, identifier, asset->get_name(), preview_id);
if (!show_names) {
item.hide_label();
}
if (shelf_.type->flag & ASSET_SHELF_TYPE_FLAG_NO_ASSET_DRAG) {
item.disable_asset_drag();
}
return true;
});
const AssetMetaData &asset_data = asset.get_metadata();
if (catalog_filter_ && !catalog_filter_->contains(asset_data.catalog_id)) {
/* Skip this asset. */
return false;
}
return true;
});
}
bool AssetView::begin_filtering(const bContext &C) const

View File

@@ -1277,7 +1277,7 @@ static Image *image_open_single(Main *bmain,
errno = 0;
if (check_exists) {
ima = BKE_image_load_exists_ex(bmain, range->filepath, &exists);
ima = BKE_image_load_exists(bmain, range->filepath, &exists);
}
else {
ima = BKE_image_load(bmain, range->filepath);

View File

@@ -108,7 +108,7 @@ static void node_label(const bNodeTree * /*ntree*/, const bNode *node, char *lab
if (!enum_label) {
name = "Unknown";
}
BLI_strncpy(label, IFACE_(name), maxlen);
BLI_strncpy(label, CTX_IFACE_(BLT_I18NCONTEXT_ID_NODETREE, name), maxlen);
}
/* Derived from `divide_round_i` but fixed to be safe and handle negative inputs. */

View File

@@ -1334,7 +1334,7 @@ ID *WM_operator_drop_load_path(bContext *C, wmOperator *op, const short idcode)
errno = 0;
if (idcode == ID_IM) {
id = (ID *)BKE_image_load_exists_ex(bmain, filepath, &exists);
id = reinterpret_cast<ID *>(BKE_image_load_exists(bmain, filepath, &exists));
}
else {
BLI_assert_unreachable();