Merge branch 'blender-v4.3-release'
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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);
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user