UI: Asset Shelf (Experimental Feature) #104831

Closed
Julian Eisel wants to merge 399 commits from asset-shelf into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
76 changed files with 729 additions and 644 deletions
Showing only changes of commit 03bd437170 - Show all commits

View File

@ -870,6 +870,26 @@ an issue but, due to internal implementation details, currently are:
thus breaking any current iteration over ``Collection.all_objects``.
.. rubric:: Do not:
.. code-block:: python
# `all_objects` is an iterator. Using it directly while performing operations on its members that will update
# the memory accessed by the `all_objects` iterator will lead to invalid memory accesses and crashes.
for object in bpy.data.collections["Collection"].all_objects:
object.hide_viewport = True
.. rubric:: Do:
.. code-block:: python
# `all_objects[:]` is an independent list generated from the iterator. As long as no objects are deleted,
# its content will remain valid even if the data accessed by the `all_objects` iterator is modified.
for object in bpy.data.collections["Collection"].all_objects[:]:
object.hide_viewport = True
sys.exit
========

@ -1 +1 @@
Subproject commit ef57e2c2c65933a68811d58b40ed62b775e9b4b0
Subproject commit 4a581c54af9b92cb670d750951b9382160f10f3e

@ -1 +1 @@
Subproject commit bde68da02fde93968dc11b52d42060ac3b81ed37
Subproject commit 0b0052bd53ad8249ed07dfb87705c338af698bde

@ -1 +1 @@
Subproject commit e6179b3b112298e131bbd0faf648bf0d392b6cdd
Subproject commit 96143b1a8b037ea3c81f065f557025db9fe1ace3

View File

@ -252,9 +252,14 @@ class NLA_OT_bake(Operator):
do_pose = 'POSE' in self.bake_types
do_object = 'OBJECT' in self.bake_types
objects = context.selected_editable_objects
if do_pose and not do_object:
objects = [obj for obj in objects if obj.pose is not None]
if do_pose and self.only_selected:
pose_bones = context.selected_pose_bones or []
armatures = {pose_bone.id_data for pose_bone in pose_bones}
objects = list(armatures)
else:
objects = context.selected_editable_objects
if do_pose and not do_object:
objects = [obj for obj in objects if obj.pose is not None]
object_action_pairs = (
[(obj, getattr(obj.animation_data, "action", None)) for obj in objects]

View File

@ -97,13 +97,12 @@ class ASSET_OT_open_containing_blend_file(Operator):
def execute(self, context):
asset_file_handle = context.asset_file_handle
asset_library_ref = context.asset_library_ref
if asset_file_handle.local_id:
self.report({'WARNING'}, "This asset is stored in the current blend file")
return {'CANCELLED'}
asset_lib_path = bpy.types.AssetHandle.get_full_library_path(asset_file_handle, asset_library_ref)
asset_lib_path = bpy.types.AssetHandle.get_full_library_path(asset_file_handle)
self.open_in_new_blender(asset_lib_path)
wm = context.window_manager

View File

@ -862,8 +862,7 @@ def asset_path_str_get(_self):
if asset_file_handle.local_id:
return "Current File"
asset_library_ref = bpy.context.asset_library_ref
return bpy.types.AssetHandle.get_full_library_path(asset_file_handle, asset_library_ref)
return bpy.types.AssetHandle.get_full_library_path(asset_file_handle)
def register_props():

View File

@ -0,0 +1,30 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup asset_system
*
* \brief Information to uniquely identify and locate an asset.
*
* https://wiki.blender.org/wiki/Source/Architecture/Asset_System/Back_End#Asset_Identifier
*/
#pragma once
#include <memory>
#include <string>
namespace blender::asset_system {
class AssetIdentifier {
std::shared_ptr<std::string> library_root_path_;
std::string relative_asset_path_;
public:
AssetIdentifier(std::shared_ptr<std::string> library_root_path, std::string relative_asset_path);
AssetIdentifier(AssetIdentifier &&) = default;
AssetIdentifier(const AssetIdentifier &) = default;
std::string full_path() const;
};
} // namespace blender::asset_system

View File

@ -24,6 +24,7 @@ struct Main;
namespace blender::asset_system {
class AssetIdentifier;
class AssetRepresentation;
class AssetStorage;
@ -35,8 +36,10 @@ class AssetStorage;
*/
class AssetLibrary {
/** If this is an asset library on disk, the top-level directory path. Normalized using
* #normalize_directory_path().*/
std::string root_path_;
* #normalize_directory_path(). Shared pointer so assets can safely point to it, and don't have
* to hold a copy (which is the size of `std::string` + the allocated buffer, if no short string
* optimization is used). With thousands of assets this might make a reasonable difference. */
std::shared_ptr<std::string> root_path_;
/** Storage for assets (better said their representations) that are considered to be part of this
* library. Assets are not automatically loaded into this when loading an asset library. Assets
@ -85,10 +88,16 @@ class AssetLibrary {
* representation is not needed anymore, it must be freed using #remove_asset(), or there will be
* leaking that's only cleared when the library storage is destructed (typically on exit or
* loading a different file).
*
* \param relative_asset_path: The path of the asset relative to the asset library root. With
* this the asset must be uniquely identifiable within the asset
* library.
*/
AssetRepresentation &add_external_asset(StringRef name, std::unique_ptr<AssetMetaData> metadata);
AssetRepresentation &add_external_asset(StringRef relative_asset_path,
StringRef name,
std::unique_ptr<AssetMetaData> metadata);
/** See #AssetLibrary::add_external_asset(). */
AssetRepresentation &add_local_id_asset(ID &id);
AssetRepresentation &add_local_id_asset(StringRef relative_asset_path, ID &id);
/** Remove an asset from the library that was added using #add_external_asset() or
* #add_local_id_asset(). Can usually be expected to be constant time complexity (worst case may
* differ).
@ -123,6 +132,12 @@ class AssetLibrary {
void on_blend_save_post(Main *bmain, PointerRNA **pointers, int num_pointers);
/**
* Create an asset identifier from the root path of this asset library and the given relative
* asset path (relative to the asset library root directory).
*/
AssetIdentifier derive_asset_identifier(StringRef relative_asset_path);
StringRefNull root_path() const;
private:

View File

@ -16,21 +16,23 @@
#include "BLI_string_ref.hh"
#include "AS_asset_identifier.hh"
struct AssetMetaData;
struct ID;
namespace blender::asset_system {
class AssetRepresentation {
struct ExternalAsset {
std::string name;
std::unique_ptr<AssetMetaData> metadata_ = nullptr;
};
AssetIdentifier identifier_;
/** Indicate if this is a local or external asset, and as such, which of the union members below
* should be used. */
const bool is_local_id_ = false;
struct ExternalAsset {
std::string name;
std::unique_ptr<AssetMetaData> metadata_ = nullptr;
};
union {
ExternalAsset external_asset_;
ID *local_asset_id_ = nullptr; /* Non-owning. */
@ -40,10 +42,12 @@ class AssetRepresentation {
public:
/** Constructs an asset representation for an external ID. The asset will not be editable. */
explicit AssetRepresentation(StringRef name, std::unique_ptr<AssetMetaData> metadata);
AssetRepresentation(AssetIdentifier &&identifier,
StringRef name,
std::unique_ptr<AssetMetaData> metadata);
/** Constructs an asset representation for an ID stored in the current file. This makes the asset
* local and fully editable. */
explicit AssetRepresentation(ID &id);
AssetRepresentation(AssetIdentifier &&identifier, ID &id);
AssetRepresentation(AssetRepresentation &&other);
/* Non-copyable type. */
AssetRepresentation(const AssetRepresentation &other) = delete;
@ -55,6 +59,8 @@ class AssetRepresentation {
/* Non-copyable type. */
AssetRepresentation &operator=(const AssetRepresentation &other) = delete;
const AssetIdentifier &get_identifier() const;
StringRefNull get_name() const;
AssetMetaData &get_metadata() const;
/** Returns if this asset is stored inside this current file, and as such fully editable. */
@ -62,3 +68,8 @@ class AssetRepresentation {
};
} // namespace blender::asset_system
/* C-Handle */
struct AssetRepresentation;
const std::string AS_asset_representation_full_path_get(const ::AssetRepresentation *asset);

View File

@ -17,6 +17,7 @@ set(SRC
intern/asset_catalog.cc
intern/asset_catalog_path.cc
intern/asset_catalog_tree.cc
intern/asset_identifier.cc
intern/asset_library.cc
intern/asset_library_service.cc
intern/asset_representation.cc
@ -26,6 +27,7 @@ set(SRC
AS_asset_catalog.hh
AS_asset_catalog_path.hh
AS_asset_catalog_tree.hh
AS_asset_identifier.hh
AS_asset_library.hh
AS_asset_representation.hh
intern/asset_library_service.hh

View File

@ -0,0 +1,27 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup asset_system
*/
#include "BLI_path_util.h"
#include <iostream>
#include "AS_asset_identifier.hh"
namespace blender::asset_system {
AssetIdentifier::AssetIdentifier(std::shared_ptr<std::string> library_root_path,
std::string relative_asset_path)
: library_root_path_(library_root_path), relative_asset_path_(relative_asset_path)
{
}
std::string AssetIdentifier::full_path() const
{
char path[FILE_MAX];
BLI_path_join(path, sizeof(path), library_root_path_->c_str(), relative_asset_path_.c_str());
return path;
}
} // namespace blender::asset_system

View File

@ -7,6 +7,7 @@
#include <memory>
#include "AS_asset_catalog_tree.hh"
#include "AS_asset_identifier.hh"
#include "AS_asset_library.h"
#include "AS_asset_library.hh"
#include "AS_asset_representation.hh"
@ -128,7 +129,7 @@ void AS_asset_library_remap_ids(const IDRemapper *mappings)
namespace blender::asset_system {
AssetLibrary::AssetLibrary(StringRef root_path)
: root_path_(utils::normalize_directory_path(root_path)),
: root_path_(std::make_shared<std::string>(utils::normalize_directory_path(root_path))),
asset_storage_(std::make_unique<AssetStorage>()),
catalog_service(std::make_unique<AssetCatalogService>())
{
@ -143,7 +144,7 @@ AssetLibrary::~AssetLibrary()
void AssetLibrary::load_catalogs()
{
auto catalog_service = std::make_unique<AssetCatalogService>(root_path_);
auto catalog_service = std::make_unique<AssetCatalogService>(root_path());
catalog_service->load_from_disk();
this->catalog_service = std::move(catalog_service);
}
@ -153,15 +154,18 @@ void AssetLibrary::refresh()
this->catalog_service->reload_catalogs();
}
AssetRepresentation &AssetLibrary::add_external_asset(StringRef name,
AssetRepresentation &AssetLibrary::add_external_asset(StringRef relative_asset_path,
StringRef name,
std::unique_ptr<AssetMetaData> metadata)
{
return asset_storage_->add_external_asset(name, std::move(metadata));
AssetIdentifier identifier = derive_asset_identifier(relative_asset_path);
return asset_storage_->add_external_asset(std::move(identifier), name, std::move(metadata));
}
AssetRepresentation &AssetLibrary::add_local_id_asset(ID &id)
AssetRepresentation &AssetLibrary::add_local_id_asset(StringRef relative_asset_path, ID &id)
{
return asset_storage_->add_local_id_asset(id);
AssetIdentifier identifier = derive_asset_identifier(relative_asset_path);
return asset_storage_->add_local_id_asset(std::move(identifier), id);
}
bool AssetLibrary::remove_asset(AssetRepresentation &asset)
@ -229,9 +233,9 @@ void AssetLibrary::on_blend_save_post(struct Main *main,
}
}
StringRefNull AssetLibrary::root_path() const
AssetIdentifier AssetLibrary::derive_asset_identifier(StringRef relative_asset_path)
{
return root_path_;
return AssetIdentifier(root_path_, relative_asset_path);
}
void AssetLibrary::refresh_catalog_simplename(struct AssetMetaData *asset_data)
@ -249,6 +253,11 @@ void AssetLibrary::refresh_catalog_simplename(struct AssetMetaData *asset_data)
STRNCPY(asset_data->catalog_simple_name, catalog->simple_name.c_str());
}
StringRefNull AssetLibrary::root_path() const
{
return *root_path_;
}
/* TODO get rid of this. */
Vector<AssetLibraryReference> all_valid_asset_library_refs()
{

View File

@ -9,6 +9,7 @@
#include "DNA_ID.h"
#include "DNA_asset_types.h"
#include "AS_asset_identifier.hh"
#include "AS_asset_representation.h"
#include "AS_asset_representation.hh"
@ -16,14 +17,17 @@
namespace blender::asset_system {
AssetRepresentation::AssetRepresentation(StringRef name, std::unique_ptr<AssetMetaData> metadata)
: is_local_id_(false), external_asset_()
AssetRepresentation::AssetRepresentation(AssetIdentifier &&identifier,
StringRef name,
std::unique_ptr<AssetMetaData> metadata)
: identifier_(identifier), is_local_id_(false), external_asset_()
{
external_asset_.name = name;
external_asset_.metadata_ = std::move(metadata);
}
AssetRepresentation::AssetRepresentation(ID &id) : is_local_id_(true), local_asset_id_(&id)
AssetRepresentation::AssetRepresentation(AssetIdentifier &&identifier, ID &id)
: identifier_(identifier), is_local_id_(true), local_asset_id_(&id)
{
if (!id.asset_data) {
throw std::invalid_argument("Passed ID is not an asset");
@ -31,7 +35,7 @@ AssetRepresentation::AssetRepresentation(ID &id) : is_local_id_(true), local_ass
}
AssetRepresentation::AssetRepresentation(AssetRepresentation &&other)
: is_local_id_(other.is_local_id_)
: identifier_(std::move(other.identifier_)), is_local_id_(other.is_local_id_)
{
if (is_local_id_) {
local_asset_id_ = other.local_asset_id_;
@ -49,6 +53,11 @@ AssetRepresentation::~AssetRepresentation()
}
}
const AssetIdentifier &AssetRepresentation::get_identifier() const
{
return identifier_;
}
StringRefNull AssetRepresentation::get_name() const
{
if (is_local_id_) {
@ -70,12 +79,20 @@ bool AssetRepresentation::is_local_id() const
} // namespace blender::asset_system
using namespace blender;
const std::string AS_asset_representation_full_path_get(const AssetRepresentation *asset_handle)
{
const asset_system::AssetRepresentation *asset =
reinterpret_cast<const asset_system::AssetRepresentation *>(asset_handle);
const asset_system::AssetIdentifier &identifier = asset->get_identifier();
return identifier.full_path();
}
/* ---------------------------------------------------------------------- */
/** \name C-API
* \{ */
using namespace blender;
const char *AS_asset_representation_name_get(const AssetRepresentation *asset_handle)
{
const asset_system::AssetRepresentation *asset =

View File

@ -15,16 +15,18 @@
namespace blender::asset_system {
AssetRepresentation &AssetStorage::add_local_id_asset(ID &id)
AssetRepresentation &AssetStorage::add_local_id_asset(AssetIdentifier &&identifier, ID &id)
{
return *local_id_assets_.lookup_key_or_add(std::make_unique<AssetRepresentation>(id));
return *local_id_assets_.lookup_key_or_add(
std::make_unique<AssetRepresentation>(std::move(identifier), id));
}
AssetRepresentation &AssetStorage::add_external_asset(StringRef name,
AssetRepresentation &AssetStorage::add_external_asset(AssetIdentifier &&identifier,
StringRef name,
std::unique_ptr<AssetMetaData> metadata)
{
return *external_assets_.lookup_key_or_add(
std::make_unique<AssetRepresentation>(name, std::move(metadata)));
std::make_unique<AssetRepresentation>(std::move(identifier), name, std::move(metadata)));
}
bool AssetStorage::remove_asset(AssetRepresentation &asset)

View File

@ -19,6 +19,7 @@ struct IDRemapper;
namespace blender::asset_system {
class AssetIdentifier;
class AssetRepresentation;
class AssetStorage {
@ -34,9 +35,11 @@ class AssetStorage {
public:
/** See #AssetLibrary::add_external_asset(). */
AssetRepresentation &add_external_asset(StringRef name, std::unique_ptr<AssetMetaData> metadata);
AssetRepresentation &add_external_asset(AssetIdentifier &&identifier,
StringRef name,
std::unique_ptr<AssetMetaData> metadata);
/** See #AssetLibrary::add_external_asset(). */
AssetRepresentation &add_local_id_asset(ID &id);
AssetRepresentation &add_local_id_asset(AssetIdentifier &&identifier, ID &id);
/** See #AssetLibrary::remove_asset(). */
bool remove_asset(AssetRepresentation &asset);

View File

@ -38,44 +38,53 @@ enum {
* Indicates whether this is direct (i.e. by local data) or indirect (i.e. by linked data) usage.
*/
IDWALK_CB_INDIRECT_USAGE = (1 << 2),
/**
* Indicates that this is a direct weak link usage, i.e. if the user is a local ID, and is using
* (pointing to) a linked ID, that usage does not make the linked ID directly linked.
*
* E.g. usages of linked collections or objects by ViewLayerCollections or Bases in scenes.
*
* See also #LIB_INDIRECT_WEAK_LINK in DNA_ID.h
*/
IDWALK_CB_DIRECT_WEAK_LINK = (1 << 3),
/**
* That ID is used as mere sub-data by its owner (only case currently: those root nodetrees in
* materials etc., and the Scene's master collections).
* This means callback shall not *do* anything, only use this as informative data if it needs it.
*/
IDWALK_CB_EMBEDDED = (1 << 3),
IDWALK_CB_EMBEDDED = (1 << 4),
/**
* That ID is not really used by its owner, it's just an internal hint/helper.
* This marks the 'from' pointers issue, like Key->from.
* How to handle that kind of cases totally depends on what caller code is doing... */
IDWALK_CB_LOOPBACK = (1 << 4),
IDWALK_CB_LOOPBACK = (1 << 5),
/** That ID is used as library override's reference by its owner. */
IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE = (1 << 5),
IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE = (1 << 6),
/** That ID pointer is not overridable. */
IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE = (1 << 6),
IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE = (1 << 7),
/**
* Indicates that this is an internal runtime ID pointer, like e.g. `ID.newid` or `ID.original`.
* \note Those should be ignored in most cases, and won't be processed/generated anyway unless
* `IDWALK_DO_INTERNAL_RUNTIME_POINTERS` option is enabled.
*/
IDWALK_CB_INTERNAL = (1 << 7),
IDWALK_CB_INTERNAL = (1 << 8),
/**
* This ID usage is fully refcounted.
* Callback is responsible to deal accordingly with #ID.us if needed.
*/
IDWALK_CB_USER = (1 << 8),
IDWALK_CB_USER = (1 << 9),
/**
* This ID usage is not refcounted, but at least one user should be generated by it (to avoid
* e.g. losing the used ID on save/reload).
* Callback is responsible to deal accordingly with #ID.us if needed.
*/
IDWALK_CB_USER_ONE = (1 << 9),
IDWALK_CB_USER_ONE = (1 << 10),
};
enum {

View File

@ -46,11 +46,6 @@ class bNodeTreeRuntime : NonCopyable, NonMovable {
*/
uint8_t runtime_flag = 0;
/** Flag to prevent re-entrant update calls. */
short is_updating = 0;
/** Generic temporary flag for recursion check (DFS/BFS). */
short done = 0;
/** Execution data.
*
* XXX It would be preferable to completely move this data out of the underlying node tree,

View File

@ -761,7 +761,8 @@ static void scene_foreach_layer_collection(LibraryForeachIDData *data, ListBase
(lc->collection->id.flag & LIB_EMBEDDED_DATA) != 0) ?
IDWALK_CB_EMBEDDED :
IDWALK_CB_NOP;
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, lc->collection, cb_flag);
BKE_LIB_FOREACHID_PROCESS_IDSUPER(
data, lc->collection, cb_flag | IDWALK_CB_DIRECT_WEAK_LINK);
scene_foreach_layer_collection(data, &lc->layer_collections);
}
}
@ -834,8 +835,11 @@ static void scene_foreach_id(ID *id, LibraryForeachIDData *data)
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, view_layer->mat_override, IDWALK_CB_USER);
BKE_view_layer_synced_ensure(scene, view_layer);
LISTBASE_FOREACH (Base *, base, BKE_view_layer_object_bases_get(view_layer)) {
BKE_LIB_FOREACHID_PROCESS_IDSUPER(
data, base->object, IDWALK_CB_NOP | IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE);
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data,
base->object,
IDWALK_CB_NOP |
IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE |
IDWALK_CB_DIRECT_WEAK_LINK);
}
BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(

View File

@ -169,7 +169,7 @@ template<
/**
* Number of bits that can be stored in the vector without doing an allocation.
*/
int64_t InlineBufferCapacity = 32,
int64_t InlineBufferCapacity = 64,
/**
* The allocator used by this vector. Should rarely be changed, except when you don't want that
* MEM_* is used internally.
@ -200,10 +200,10 @@ class BitVector {
int64_t capacity_in_bits_;
/** Used for allocations when the inline buffer is too small. */
Allocator allocator_;
BLI_NO_UNIQUE_ADDRESS Allocator allocator_;
/** Contains the bits as long as the vector is small enough. */
TypedBuffer<uint8_t, BytesInInlineBuffer> inline_buffer_;
BLI_NO_UNIQUE_ADDRESS TypedBuffer<uint8_t, BytesInInlineBuffer> inline_buffer_;
public:
BitVector(Allocator allocator = {}) noexcept : allocator_(allocator)

View File

@ -33,14 +33,14 @@
*
* There are three main ways to provide a hash table implementation with a custom hash function.
*
* - When you want to provide a default hash function for your own custom type: Add a `hash`
* - When you want to provide a default hash function for your own custom type: Add a `hash()`
* member function to it. The function should return `uint64_t` and take no arguments. This
* method will be called by the default implementation of #DefaultHash. It will automatically be
* used by hash table implementations.
*
* - When you want to provide a default hash function for a type that you cannot modify: Add a new
* specialization to the #DefaultHash struct. This can be done by writing code like below in
* either global or BLI namespace.
* either global or `blender` namespace.
*
* template<> struct blender::DefaultHash<TheType> {
* uint64_t operator()(const TheType &value) const {

View File

@ -102,6 +102,41 @@ template<typename T, BLI_ENABLE_IF((is_math_float_type<T>))> inline T fract(cons
return a - std::floor(a);
}
template<typename T> inline T cos(const T &a)
{
return std::cos(a);
}
template<typename T> inline T sin(const T &a)
{
return std::sin(a);
}
template<typename T> inline T tan(const T &a)
{
return std::tan(a);
}
template<typename T> inline T acos(const T &a)
{
return std::acos(a);
}
template<typename T> inline T asin(const T &a)
{
return std::asin(a);
}
template<typename T> inline T atan(const T &a)
{
return std::atan(a);
}
template<typename T> inline T atan2(const T &a, const T &b)
{
return std::atan2(a, b);
}
template<typename T,
typename FactorT,
BLI_ENABLE_IF((std::is_arithmetic_v<T>)),

View File

@ -51,6 +51,7 @@
#include "BLI_endian_switch.h"
#include "BLI_ghash.h"
#include "BLI_linklist.h"
#include "BLI_map.hh"
#include "BLI_math.h"
#include "BLI_memarena.h"
#include "BLI_mempool.h"
@ -229,119 +230,19 @@ static const char *library_parent_filepath(Library *lib)
/** \name OldNewMap API
* \{ */
struct OldNew {
const void *oldp;
struct NewAddress {
void *newp;
/* `nr` is "user count" for data, and ID code for libdata. */
int nr;
};
struct OldNewMap {
/* Array that stores the actual entries. */
OldNew *entries;
int nentries;
/* Hash-map that stores indices into the `entries` array. */
int32_t *map;
int capacity_exp;
blender::Map<const void *, NewAddress> map;
};
#define ENTRIES_CAPACITY(onm) (1ll << (onm)->capacity_exp)
#define MAP_CAPACITY(onm) (1ll << ((onm)->capacity_exp + 1))
#define SLOT_MASK(onm) (MAP_CAPACITY(onm) - 1)
#define DEFAULT_SIZE_EXP 6
#define PERTURB_SHIFT 5
/* based on the probing algorithm used in Python dicts. */
#define ITER_SLOTS(onm, KEY, SLOT_NAME, INDEX_NAME) \
uint32_t hash = BLI_ghashutil_ptrhash(KEY); \
uint32_t mask = SLOT_MASK(onm); \
uint perturb = hash; \
int SLOT_NAME = mask & hash; \
int INDEX_NAME = onm->map[SLOT_NAME]; \
for (;; SLOT_NAME = mask & ((5 * SLOT_NAME) + 1 + perturb), \
perturb >>= PERTURB_SHIFT, \
INDEX_NAME = onm->map[SLOT_NAME])
static void oldnewmap_insert_index_in_map(OldNewMap *onm, const void *ptr, int index)
{
ITER_SLOTS (onm, ptr, slot, stored_index) {
if (stored_index == -1) {
onm->map[slot] = index;
break;
}
}
}
static void oldnewmap_insert_or_replace(OldNewMap *onm, OldNew entry)
{
ITER_SLOTS (onm, entry.oldp, slot, index) {
if (index == -1) {
onm->entries[onm->nentries] = entry;
onm->map[slot] = onm->nentries;
onm->nentries++;
break;
}
if (onm->entries[index].oldp == entry.oldp) {
onm->entries[index] = entry;
break;
}
}
}
static OldNew *oldnewmap_lookup_entry(const OldNewMap *onm, const void *addr)
{
ITER_SLOTS (onm, addr, slot, index) {
if (index >= 0) {
OldNew *entry = &onm->entries[index];
if (entry->oldp == addr) {
return entry;
}
}
else {
return nullptr;
}
}
}
static void oldnewmap_clear_map(OldNewMap *onm)
{
memset(onm->map, 0xFF, MAP_CAPACITY(onm) * sizeof(*onm->map));
}
static void oldnewmap_increase_size(OldNewMap *onm)
{
onm->capacity_exp++;
onm->entries = static_cast<OldNew *>(
MEM_reallocN(onm->entries, sizeof(*onm->entries) * ENTRIES_CAPACITY(onm)));
onm->map = static_cast<int32_t *>(MEM_reallocN(onm->map, sizeof(*onm->map) * MAP_CAPACITY(onm)));
oldnewmap_clear_map(onm);
for (int i = 0; i < onm->nentries; i++) {
oldnewmap_insert_index_in_map(onm, onm->entries[i].oldp, i);
}
}
/* Public OldNewMap API */
static void oldnewmap_init_data(OldNewMap *onm, const int capacity_exp)
{
memset(onm, 0x0, sizeof(*onm));
onm->capacity_exp = capacity_exp;
onm->entries = static_cast<OldNew *>(
MEM_malloc_arrayN(ENTRIES_CAPACITY(onm), sizeof(*onm->entries), "OldNewMap.entries"));
onm->map = static_cast<int32_t *>(
MEM_malloc_arrayN(MAP_CAPACITY(onm), sizeof(*onm->map), "OldNewMap.map"));
oldnewmap_clear_map(onm);
}
static OldNewMap *oldnewmap_new()
{
OldNewMap *onm = static_cast<OldNewMap *>(MEM_mallocN(sizeof(*onm), "OldNewMap"));
oldnewmap_init_data(onm, DEFAULT_SIZE_EXP);
return onm;
return MEM_new<OldNewMap>(__func__);
}
static void oldnewmap_insert(OldNewMap *onm, const void *oldaddr, void *newaddr, int nr)
@ -350,15 +251,7 @@ static void oldnewmap_insert(OldNewMap *onm, const void *oldaddr, void *newaddr,
return;
}
if (UNLIKELY(onm->nentries == ENTRIES_CAPACITY(onm))) {
oldnewmap_increase_size(onm);
}
OldNew entry;
entry.oldp = oldaddr;
entry.newp = newaddr;
entry.nr = nr;
oldnewmap_insert_or_replace(onm, entry);
onm->map.add_overwrite(oldaddr, NewAddress{newaddr, nr});
}
static void oldnewmap_lib_insert(FileData *fd, const void *oldaddr, ID *newaddr, int nr)
@ -373,7 +266,7 @@ void blo_do_versions_oldnewmap_insert(OldNewMap *onm, const void *oldaddr, void
static void *oldnewmap_lookup_and_inc(OldNewMap *onm, const void *addr, bool increase_users)
{
OldNew *entry = oldnewmap_lookup_entry(onm, addr);
NewAddress *entry = onm->map.lookup_ptr(addr);
if (entry == nullptr) {
return nullptr;
}
@ -383,7 +276,7 @@ static void *oldnewmap_lookup_and_inc(OldNewMap *onm, const void *addr, bool inc
return entry->newp;
}
/* for libdata, OldNew.nr has ID code, no increment */
/* for libdata, NewAddress.nr has ID code, no increment */
static void *oldnewmap_liblookup(OldNewMap *onm, const void *addr, const void *lib)
{
if (addr == nullptr) {
@ -403,34 +296,19 @@ static void *oldnewmap_liblookup(OldNewMap *onm, const void *addr, const void *l
static void oldnewmap_clear(OldNewMap *onm)
{
/* Free unused data. */
for (int i = 0; i < onm->nentries; i++) {
OldNew *entry = &onm->entries[i];
if (entry->nr == 0) {
MEM_freeN(entry->newp);
entry->newp = nullptr;
for (NewAddress &new_addr : onm->map.values()) {
if (new_addr.nr == 0) {
MEM_freeN(new_addr.newp);
}
}
MEM_freeN(onm->entries);
MEM_freeN(onm->map);
oldnewmap_init_data(onm, DEFAULT_SIZE_EXP);
onm->map.clear();
}
static void oldnewmap_free(OldNewMap *onm)
{
MEM_freeN(onm->entries);
MEM_freeN(onm->map);
MEM_freeN(onm);
MEM_delete(onm);
}
#undef ENTRIES_CAPACITY
#undef MAP_CAPACITY
#undef SLOT_MASK
#undef DEFAULT_SIZE_EXP
#undef PERTURB_SHIFT
#undef ITER_SLOTS
/** \} */
/* -------------------------------------------------------------------- */
@ -1555,13 +1433,11 @@ static void change_link_placeholder_to_real_ID_pointer_fd(FileData *fd,
const void *old,
void *newp)
{
for (int i = 0; i < fd->libmap->nentries; i++) {
OldNew *entry = &fd->libmap->entries[i];
if (old == entry->newp && entry->nr == ID_LINK_PLACEHOLDER) {
entry->newp = newp;
for (NewAddress &entry : fd->libmap->map.values()) {
if (old == entry.newp && entry.nr == ID_LINK_PLACEHOLDER) {
entry.newp = newp;
if (newp) {
entry->nr = GS(((ID *)newp)->name);
entry.nr = GS(((ID *)newp)->name);
}
}
}
@ -1640,12 +1516,10 @@ void blo_make_packed_pointer_map(FileData *fd, Main *oldmain)
void blo_end_packed_pointer_map(FileData *fd, Main *oldmain)
{
OldNew *entry = fd->packedmap->entries;
/* used entries were restored, so we put them to zero */
for (int i = 0; i < fd->packedmap->nentries; i++, entry++) {
if (entry->nr > 0) {
entry->newp = nullptr;
for (NewAddress &entry : fd->packedmap->map.values()) {
if (entry.nr > 0) {
entry.newp = nullptr;
}
}

View File

@ -102,6 +102,7 @@
#include "BKE_layer.h"
#include "BKE_lib_id.h"
#include "BKE_lib_override.h"
#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_node.h"
#include "BKE_packedFile.h"
@ -1083,6 +1084,31 @@ static void write_thumb(WriteData *wd, const BlendThumbnail *thumb)
/** \name File Writing (Private)
* \{ */
/* Helper callback for checking linked IDs used by given ID (assumed local), to ensure directly
* linked data is tagged accordingly. */
static int write_id_direct_linked_data_process_cb(LibraryIDLinkCallbackData *cb_data)
{
ID *id_self = cb_data->id_self;
ID *id = *cb_data->id_pointer;
const int cb_flag = cb_data->cb_flag;
if (id == nullptr || !ID_IS_LINKED(id)) {
return IDWALK_RET_NOP;
}
BLI_assert(!ID_IS_LINKED(id_self));
BLI_assert((cb_flag & IDWALK_CB_INDIRECT_USAGE) == 0);
UNUSED_VARS_NDEBUG(id_self);
if (cb_flag & IDWALK_CB_DIRECT_WEAK_LINK) {
id_lib_indirect_weak_link(id);
}
else {
id_lib_extern(id);
}
return IDWALK_RET_NOP;
}
/* if MemFile * there's filesave to memory */
static bool write_file_handle(Main *mainvar,
WriteWrap *ww,
@ -1097,11 +1123,24 @@ static bool write_file_handle(Main *mainvar,
char buf[16];
WriteData *wd;
blo_split_main(&mainlist, mainvar);
wd = mywrite_begin(ww, compare, current);
BlendWriter writer = {wd};
/* Clear 'directly linked' flag for all linked data, these are not necessarily valid/up-to-date
* info, they will be re-generated while write code is processing local IDs below. */
if (!wd->use_memfile) {
ID *id_iter;
FOREACH_MAIN_ID_BEGIN (mainvar, id_iter) {
if (ID_IS_LINKED(id_iter)) {
id_iter->tag |= LIB_TAG_INDIRECT;
id_iter->tag &= ~LIB_TAG_EXTERN;
}
}
FOREACH_MAIN_ID_END;
}
blo_split_main(&mainlist, mainvar);
BLI_snprintf(buf,
sizeof(buf),
"BLENDER%c%c%.3d",
@ -1169,6 +1208,12 @@ static bool write_file_handle(Main *mainvar,
const bool do_override = !ELEM(override_storage, nullptr, bmain) &&
ID_IS_OVERRIDE_LIBRARY_REAL(id);
/* If not writing undo data, properly set directly linked IDs as `LIB_TAG_EXTERN`. */
if (!wd->use_memfile) {
BKE_library_foreach_ID_link(
bmain, id, write_id_direct_linked_data_process_cb, nullptr, IDWALK_READONLY);
}
if (do_override) {
BKE_lib_override_library_operations_store_start(bmain, override_storage, id);
}

View File

@ -1408,6 +1408,7 @@ static void drw_subdiv_compute_dispatch(const DRWSubdivCache *cache,
}
void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache,
GPUVertBuf *flags_buffer,
GPUVertBuf *pos_nor,
GPUVertBuf *orco)
{
@ -1460,6 +1461,10 @@ void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache,
GPU_vertbuf_bind_as_ssbo(patch_arrays_buffer, binding_point++);
GPU_vertbuf_bind_as_ssbo(patch_index_buffer, binding_point++);
GPU_vertbuf_bind_as_ssbo(patch_param_buffer, binding_point++);
if (flags_buffer) {
GPU_vertbuf_bind_as_ssbo(flags_buffer, binding_point);
}
binding_point++;
GPU_vertbuf_bind_as_ssbo(pos_nor, binding_point++);
if (orco) {
GPU_vertbuf_bind_as_ssbo(src_extra_buffer, binding_point++);

View File

@ -242,6 +242,7 @@ void draw_subdiv_finalize_custom_normals(const DRWSubdivCache *cache,
GPUVertBuf *pos_nor);
void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache,
GPUVertBuf *flags_buffer,
struct GPUVertBuf *pos_nor,
struct GPUVertBuf *orco);

View File

@ -236,7 +236,7 @@ static void extract_edituv_stretch_angle_init_subdiv(const DRWSubdivCache *subdi
draw_subdiv_get_pos_nor_format(),
subdiv_cache->num_subdiv_loops + loose_geom.loop_len);
draw_subdiv_extract_pos_nor(subdiv_cache, pos_nor, nullptr);
draw_subdiv_extract_pos_nor(subdiv_cache, nullptr, pos_nor, nullptr);
}
/* UVs are stored contiguously so we need to compute the offset in the UVs buffer for the active

View File

@ -200,8 +200,26 @@ static GPUVertFormat *get_custom_normals_format()
return &format;
}
static void extract_vertex_flags(const MeshRenderData *mr, char *flags)
{
for (int i = 0; i < mr->vert_len; i++) {
char *flag = &flags[i];
const bool vert_hidden = mr->hide_vert && mr->hide_vert[i];
/* Flag for paint mode overlay. */
if (vert_hidden || ((mr->v_origindex) && (mr->v_origindex[i] == ORIGINDEX_NONE))) {
*flag = -1;
}
else if (mr->select_vert && mr->select_vert[i]) {
*flag = 1;
}
else {
*flag = 0;
}
}
}
static void extract_pos_nor_init_subdiv(const DRWSubdivCache *subdiv_cache,
const MeshRenderData * /*mr*/,
const MeshRenderData *mr,
MeshBatchCache *cache,
void *buffer,
void * /*data*/)
@ -217,6 +235,17 @@ static void extract_pos_nor_init_subdiv(const DRWSubdivCache *subdiv_cache,
return;
}
GPUVertBuf *flags_buffer = GPU_vertbuf_calloc();
static GPUVertFormat flag_format = {0};
if (flag_format.attr_len == 0) {
GPU_vertformat_attr_add(&flag_format, "flag", GPU_COMP_I32, 1, GPU_FETCH_INT);
}
GPU_vertbuf_init_with_format(flags_buffer, &flag_format);
GPU_vertbuf_data_alloc(flags_buffer, divide_ceil_u(mr->vert_len, 4));
char *flags = static_cast<char *>(GPU_vertbuf_get_data(flags_buffer));
extract_vertex_flags(mr, flags);
GPU_vertbuf_tag_dirty(flags_buffer);
GPUVertBuf *orco_vbo = cache->final.buff.vbo.orco;
if (orco_vbo) {
@ -231,7 +260,7 @@ static void extract_pos_nor_init_subdiv(const DRWSubdivCache *subdiv_cache,
GPU_vertbuf_init_build_on_device(orco_vbo, &format, subdiv_cache->num_subdiv_loops);
}
draw_subdiv_extract_pos_nor(subdiv_cache, vbo, orco_vbo);
draw_subdiv_extract_pos_nor(subdiv_cache, flags_buffer, vbo, orco_vbo);
if (subdiv_cache->use_custom_loop_normals) {
Mesh *coarse_mesh = subdiv_cache->mesh;
@ -279,6 +308,8 @@ static void extract_pos_nor_init_subdiv(const DRWSubdivCache *subdiv_cache,
GPU_vertbuf_discard(vertex_normals);
GPU_vertbuf_discard(subdiv_loop_subdiv_vert_index);
}
GPU_vertbuf_discard(flags_buffer);
}
static void extract_pos_nor_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,

View File

@ -87,16 +87,30 @@ layout(std430, binding = 11) readonly buffer extraCoarseFaceData
uint extra_coarse_face_data[];
};
#else
layout(std430, binding = 8) writeonly buffer outputVertexData
layout(std430, binding = 8) readonly buffer inputFlagsBuffer
{
int flags_buffer[]; /*char*/
};
float get_flag(int vertex)
{
int char4 = flags_buffer[vertex / 4];
int flag = (char4 >> ((vertex % 4) * 8)) & 0xFF;
if (flag >= 128) {
flag = -128 + (flag - 128);
}
return float(flag);
}
layout(std430, binding = 9) writeonly buffer outputVertexData
{
PosNorLoop output_verts[];
};
# if defined(ORCO_EVALUATION)
layout(std430, binding = 9) buffer src_extra_buffer
layout(std430, binding = 10) buffer src_extra_buffer
{
float srcExtraVertexBuffer[];
};
layout(std430, binding = 10) writeonly buffer outputOrcoData
layout(std430, binding = 11) writeonly buffer outputOrcoData
{
vec4 output_orcos[];
};
@ -463,6 +477,9 @@ void main()
if (origindex == -1) {
flag = -1.0;
}
else {
flag = get_flag(origindex);
}
PosNorLoop vertex_data;
set_vertex_pos(vertex_data, pos);

View File

@ -249,16 +249,15 @@ static void poselib_tempload_exit(PoseBlendData *pbd)
static bAction *poselib_blend_init_get_action(bContext *C, wmOperator *op)
{
bool asset_handle_valid;
const AssetLibraryReference *asset_library_ref = CTX_wm_asset_library_ref(C);
const AssetHandle asset_handle = CTX_wm_asset_handle(C, &asset_handle_valid);
/* Poll callback should check. */
BLI_assert((asset_library_ref != NULL) && asset_handle_valid);
BLI_assert(asset_handle_valid);
PoseBlendData *pbd = op->customdata;
pbd->temp_id_consumer = ED_asset_temp_id_consumer_create(&asset_handle);
return (bAction *)ED_asset_temp_id_consumer_ensure_local_id(
pbd->temp_id_consumer, C, asset_library_ref, ID_AC, CTX_data_main(C), op->reports);
pbd->temp_id_consumer, ID_AC, CTX_data_main(C), op->reports);
}
static bAction *flip_pose(bContext *C, Object *ob, bAction *action)
@ -508,11 +507,9 @@ static bool poselib_asset_in_context(bContext *C)
{
bool asset_handle_valid;
/* Check whether the context provides the asset data needed to add a pose. */
const AssetLibraryReference *asset_library_ref = CTX_wm_asset_library_ref(C);
AssetHandle asset_handle = CTX_wm_asset_handle(C, &asset_handle_valid);
const AssetHandle asset_handle = CTX_wm_asset_handle(C, &asset_handle_valid);
return (asset_library_ref != NULL) && asset_handle_valid &&
(ED_asset_handle_get_id_type(&asset_handle) == ID_AC);
return asset_handle_valid && (ED_asset_handle_get_id_type(&asset_handle) == ID_AC);
}
/* Poll callback for operators that require existing PoseLib data (with poses) to work. */

View File

@ -27,9 +27,7 @@ struct AssetMetaData *ED_asset_handle_get_metadata(const struct AssetHandle *ass
struct ID *ED_asset_handle_get_local_id(const struct AssetHandle *asset);
ID_Type ED_asset_handle_get_id_type(const struct AssetHandle *asset);
int ED_asset_handle_get_preview_icon_id(const struct AssetHandle *asset);
void ED_asset_handle_get_full_library_path(const struct bContext *C,
const struct AssetLibraryReference *asset_library_ref,
const struct AssetHandle *asset,
void ED_asset_handle_get_full_library_path(const struct AssetHandle *asset,
char r_full_lib_path[]);
#ifdef __cplusplus
@ -41,9 +39,7 @@ void ED_asset_handle_get_full_library_path(const struct bContext *C,
namespace blender::ed::asset {
/** If the ID already exists in the database, return it, otherwise add it. */
ID *get_local_id_from_asset_or_append_and_reuse(Main &bmain,
const AssetLibraryReference &library_ref,
AssetHandle asset);
ID *get_local_id_from_asset_or_append_and_reuse(Main &bmain, AssetHandle asset);
} // namespace blender::ed::asset

View File

@ -51,7 +51,6 @@ void ED_assetlist_storage_id_remap(struct ID *id_old, struct ID *id_new);
void ED_assetlist_storage_exit(void);
struct ImBuf *ED_assetlist_asset_image_get(const AssetHandle *asset_handle);
const char *ED_assetlist_library_path(const struct AssetLibraryReference *library_reference);
/**
* \return True if the region needs a UI redraw.

View File

@ -15,10 +15,6 @@ struct AssetLibraryReference;
struct FileDirEntry;
struct bContext;
std::string ED_assetlist_asset_filepath_get(const bContext *C,
const AssetLibraryReference &library_reference,
const AssetHandle &asset_handle);
/* Can return false to stop iterating. */
using AssetListIterFn = blender::FunctionRef<bool(AssetHandle)>;
void ED_assetlist_iterate(const AssetLibraryReference &library_reference, AssetListIterFn fn);

View File

@ -27,13 +27,10 @@ struct bContext;
AssetTempIDConsumer *ED_asset_temp_id_consumer_create(const struct AssetHandle *handle);
void ED_asset_temp_id_consumer_free(AssetTempIDConsumer **consumer);
struct ID *ED_asset_temp_id_consumer_ensure_local_id(
AssetTempIDConsumer *consumer,
const struct bContext *C,
const struct AssetLibraryReference *asset_library_ref,
ID_Type id_type,
struct Main *bmain,
struct ReportList *reports);
struct ID *ED_asset_temp_id_consumer_ensure_local_id(AssetTempIDConsumer *consumer,
ID_Type id_type,
struct Main *bmain,
struct ReportList *reports);
#ifdef __cplusplus
}

View File

@ -6,7 +6,9 @@
#include <string>
#include "AS_asset_identifier.hh"
#include "AS_asset_representation.h"
#include "AS_asset_representation.hh"
#include "DNA_space_types.h"
@ -42,14 +44,12 @@ int ED_asset_handle_get_preview_icon_id(const AssetHandle *asset)
return asset->file_data->preview_icon_id;
}
void ED_asset_handle_get_full_library_path(const bContext *C,
const AssetLibraryReference *asset_library_ref,
const AssetHandle *asset,
void ED_asset_handle_get_full_library_path(const AssetHandle *asset_handle,
char r_full_lib_path[FILE_MAX_LIBEXTRA])
{
*r_full_lib_path = '\0';
std::string asset_path = ED_assetlist_asset_filepath_get(C, *asset_library_ref, *asset);
std::string asset_path = AS_asset_representation_full_path_get(asset_handle->file_data->asset);
if (asset_path.empty()) {
return;
}
@ -59,16 +59,14 @@ void ED_asset_handle_get_full_library_path(const bContext *C,
namespace blender::ed::asset {
ID *get_local_id_from_asset_or_append_and_reuse(Main &bmain,
const AssetLibraryReference &library_ref,
const AssetHandle asset)
ID *get_local_id_from_asset_or_append_and_reuse(Main &bmain, const AssetHandle asset)
{
if (ID *local_id = ED_asset_handle_get_local_id(&asset)) {
return local_id;
}
char blend_path[FILE_MAX_LIBEXTRA];
ED_asset_handle_get_full_library_path(nullptr, &library_ref, &asset, blend_path);
ED_asset_handle_get_full_library_path(&asset, blend_path);
const char *id_name = ED_asset_handle_get_name(&asset);
return WM_file_append_datablock(&bmain,

View File

@ -24,8 +24,6 @@
#include "BKE_preferences.h"
#include "ED_fileselect.h"
#include "WM_api.h"
/* XXX uses private header of file-space. */
@ -121,7 +119,6 @@ class AssetList : NonCopyable {
int size() const;
void tagMainDataDirty() const;
void remapID(ID *id_old, ID *id_new) const;
StringRef filepath() const;
};
AssetList::AssetList(eFileSelectType filesel_type, const AssetLibraryReference &asset_library_ref)
@ -286,11 +283,6 @@ void AssetList::remapID(ID * /*id_old*/, ID * /*id_new*/) const
tagMainDataDirty();
}
StringRef AssetList::filepath() const
{
return filelist_dir(filelist_);
}
/** \} */
/* -------------------------------------------------------------------- */
@ -457,46 +449,6 @@ void ED_assetlist_iterate(const AssetLibraryReference &library_reference, AssetL
}
}
/* TODO hack to use the File Browser path, so we can keep all the import logic handled by the asset
* API. Get rid of this once the File Browser is integrated better with the asset list. */
static const char *assetlist_library_path_from_sfile_get_hack(const bContext *C)
{
SpaceFile *sfile = CTX_wm_space_file(C);
if (!sfile || !ED_fileselect_is_asset_browser(sfile)) {
return nullptr;
}
FileAssetSelectParams *asset_select_params = ED_fileselect_get_asset_params(sfile);
if (!asset_select_params) {
return nullptr;
}
return filelist_dir(sfile->files);
}
std::string ED_assetlist_asset_filepath_get(const bContext *C,
const AssetLibraryReference &library_reference,
const AssetHandle &asset_handle)
{
if (ED_asset_handle_get_local_id(&asset_handle) ||
!ED_asset_handle_get_metadata(&asset_handle)) {
return {};
}
const char *library_path = ED_assetlist_library_path(&library_reference);
if (!library_path && C) {
library_path = assetlist_library_path_from_sfile_get_hack(C);
}
if (!library_path) {
return {};
}
const char *asset_relpath = asset_handle.file_data->relpath;
char path[FILE_MAX_LIBEXTRA];
BLI_path_join(path, sizeof(path), library_path, asset_relpath);
return path;
}
ImBuf *ED_assetlist_asset_image_get(const AssetHandle *asset_handle)
{
ImBuf *imbuf = filelist_file_getimage(asset_handle->file_data);
@ -507,15 +459,6 @@ ImBuf *ED_assetlist_asset_image_get(const AssetHandle *asset_handle)
return filelist_geticon_image_ex(asset_handle->file_data);
}
const char *ED_assetlist_library_path(const AssetLibraryReference *library_reference)
{
AssetList *list = AssetListStorage::lookup_list(*library_reference);
if (list) {
return list->filepath().data();
}
return nullptr;
}
bool ED_assetlist_listen(const AssetLibraryReference *library_reference,
const wmNotifier *notifier)
{

View File

@ -44,15 +44,11 @@ class AssetTemporaryIDConsumer : NonCopyable, NonMovable {
return ED_asset_handle_get_local_id(&handle_);
}
ID *import_id(const bContext *C,
const AssetLibraryReference &asset_library_ref,
ID_Type id_type,
Main &bmain,
ReportList &reports)
ID *import_id(ID_Type id_type, Main &bmain, ReportList &reports)
{
const char *asset_name = ED_asset_handle_get_name(&handle_);
char blend_file_path[FILE_MAX_LIBEXTRA];
ED_asset_handle_get_full_library_path(C, &asset_library_ref, &handle_, blend_file_path);
ED_asset_handle_get_full_library_path(&handle_, blend_file_path);
temp_lib_context_ = BLO_library_temp_load_id(
&bmain, blend_file_path, id_type, asset_name, &reports);
@ -84,13 +80,11 @@ void ED_asset_temp_id_consumer_free(AssetTempIDConsumer **consumer)
}
ID *ED_asset_temp_id_consumer_ensure_local_id(AssetTempIDConsumer *consumer_,
const bContext *C,
const AssetLibraryReference *asset_library_ref,
ID_Type id_type,
Main *bmain,
ReportList *reports)
{
if (!(consumer_ && asset_library_ref && bmain && reports)) {
if (!(consumer_ && bmain && reports)) {
return nullptr;
}
AssetTemporaryIDConsumer *consumer = reinterpret_cast<AssetTemporaryIDConsumer *>(consumer_);
@ -98,5 +92,5 @@ ID *ED_asset_temp_id_consumer_ensure_local_id(AssetTempIDConsumer *consumer_,
if (ID *local_id = consumer->get_local_id()) {
return local_id;
}
return consumer->import_id(C, *asset_library_ref, id_type, *bmain, *reports);
return consumer->import_id(id_type, *bmain, *reports);
}

View File

@ -2229,10 +2229,8 @@ static void gpencil_paint_initstroke(tGPsdata *p,
* -> If there are no strokes in that frame, don't add a new empty frame
*/
if (gpl->actframe && gpl->actframe->strokes.first) {
if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) {
short frame_mode = IS_AUTOKEY_ON(scene) ? GP_GETFRAME_ADD_COPY : GP_GETFRAME_USE_PREV;
gpl->actframe = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, frame_mode);
}
short frame_mode = IS_AUTOKEY_ON(scene) ? GP_GETFRAME_ADD_COPY : GP_GETFRAME_USE_PREV;
gpl->actframe = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, frame_mode);
has_layer_to_erase = true;
break;
}

View File

@ -36,9 +36,7 @@ struct AssetViewListData {
bool show_names;
};
static void asset_view_item_but_drag_set(uiBut *but,
AssetViewListData *list_data,
AssetHandle *asset_handle)
static void asset_view_item_but_drag_set(uiBut *but, AssetHandle *asset_handle)
{
ID *id = ED_asset_handle_get_local_id(asset_handle);
if (id != nullptr) {
@ -49,8 +47,7 @@ static void asset_view_item_but_drag_set(uiBut *but,
char blend_path[FILE_MAX_LIBEXTRA];
/* Context can be null here, it's only needed for a File Browser specific hack that should go
* away before too long. */
ED_asset_handle_get_full_library_path(
nullptr, &list_data->asset_library_ref, asset_handle, blend_path);
ED_asset_handle_get_full_library_path(asset_handle, blend_path);
if (blend_path[0]) {
ImBuf *imbuf = ED_assetlist_asset_image_get(asset_handle);
@ -107,7 +104,7 @@ static void asset_view_draw_item(uiList *ui_list,
/* NOLINTNEXTLINE: bugprone-suspicious-enum-usage */
UI_HAS_ICON | UI_BUT_ICON_PREVIEW);
if (!ui_list->dyn_data->custom_drag_optype) {
asset_view_item_but_drag_set(but, list_data, asset_handle);
asset_view_item_but_drag_set(but, asset_handle);
}
}

View File

@ -2859,12 +2859,12 @@ static bool file_delete_poll(bContext *C)
return false;
}
static bool file_delete_single(const FileSelectParams *params,
static bool file_delete_single(const struct FileList *files,
FileDirEntry *file,
const char **r_error_message)
{
char str[FILE_MAX];
BLI_path_join(str, sizeof(str), params->dir, file->relpath);
char str[FILE_MAX_LIBEXTRA];
filelist_file_get_full_path(files, file, str);
if (BLI_delete_soft(str, r_error_message) != 0 || BLI_exists(str)) {
return false;
}
@ -2876,7 +2876,6 @@ static int file_delete_exec(bContext *C, wmOperator *op)
{
wmWindowManager *wm = CTX_wm_manager(C);
SpaceFile *sfile = CTX_wm_space_file(C);
FileSelectParams *params = ED_fileselect_get_active_params(sfile);
int numfiles = filelist_files_ensure(sfile->files);
const char *error_message = NULL;
@ -2885,7 +2884,7 @@ static int file_delete_exec(bContext *C, wmOperator *op)
for (int i = 0; i < numfiles; i++) {
if (filelist_entry_select_index_get(sfile->files, i, CHECK_ALL)) {
FileDirEntry *file = filelist_file(sfile->files, i);
if (!file_delete_single(params, file, &error_message)) {
if (!file_delete_single(sfile->files, file, &error_message)) {
report_error = true;
}
}

View File

@ -1139,6 +1139,18 @@ void filelist_free_icons(void)
}
}
void filelist_file_get_full_path(const FileList *filelist, const FileDirEntry *file, char *r_path)
{
if (file->asset) {
const std::string asset_path = AS_asset_representation_full_path_get(file->asset);
BLI_strncpy(r_path, asset_path.c_str(), FILE_MAX_LIBEXTRA);
return;
}
const char *root = filelist_dir(filelist);
BLI_path_join(r_path, FILE_MAX_LIBEXTRA, root, file->relpath);
}
static FileDirEntry *filelist_geticon_get_file(struct FileList *filelist, const int index)
{
BLI_assert(G.background == false);
@ -1183,8 +1195,8 @@ ImBuf *filelist_geticon_image(struct FileList *filelist, const int index)
return filelist_geticon_image_ex(file);
}
static int filelist_geticon_ex(const FileDirEntry *file,
const char *root,
static int filelist_geticon_ex(const FileList *filelist,
const FileDirEntry *file,
const bool is_main,
const bool ignore_libdir)
{
@ -1222,8 +1234,8 @@ static int filelist_geticon_ex(const FileDirEntry *file,
if (file->redirection_path) {
target = file->redirection_path;
}
else if (root) {
BLI_path_join(fullpath, sizeof(fullpath), root, file->relpath);
else if (filelist) {
filelist_file_get_full_path(filelist, file, fullpath);
BLI_path_slash_ensure(fullpath, sizeof(fullpath));
}
for (; tfsm; tfsm = tfsm->next) {
@ -1303,13 +1315,13 @@ int filelist_geticon(struct FileList *filelist, const int index, const bool is_m
{
FileDirEntry *file = filelist_geticon_get_file(filelist, index);
return filelist_geticon_ex(file, filelist->filelist.root, is_main, false);
return filelist_geticon_ex(filelist, file, is_main, false);
}
int ED_file_icon(const FileDirEntry *file)
{
return file->preview_icon_id ? file->preview_icon_id :
filelist_geticon_ex(file, nullptr, false, false);
filelist_geticon_ex(nullptr, file, false, false);
}
static bool filelist_intern_entry_is_main_file(const FileListInternEntry *intern_entry)
@ -1636,8 +1648,7 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry
BLI_strncpy(preview->filepath, entry->redirection_path, FILE_MAXDIR);
}
else {
BLI_path_join(
preview->filepath, sizeof(preview->filepath), filelist->filelist.root, entry->relpath);
filelist_file_get_full_path(filelist, entry, preview->filepath);
}
// printf("%s: %d - %s\n", __func__, preview->index, preview->filepath);
@ -1967,7 +1978,7 @@ static const char *fileentry_uiname(const char *root, FileListInternEntry *entry
return BLI_strdup(name);
}
const char *filelist_dir(struct FileList *filelist)
const char *filelist_dir(const FileList *filelist)
{
return filelist->filelist.root;
}
@ -2905,7 +2916,65 @@ struct TodoDir {
char *dir;
};
static int filelist_readjob_list_dir(const char *root,
struct FileListReadJob {
ThreadMutex lock;
char main_name[FILE_MAX];
Main *current_main;
FileList *filelist;
/** The path currently being read, relative to the filelist root directory. Needed for recursive
* reading. The full file path is then composed like: `<filelist root>/<cur_relbase>/<file name>.
* (whereby the file name may also be a library path within a .blend, e.g.
* `Materials/Material.001`). */
char cur_relbase[FILE_MAX_LIBEXTRA];
/** Set to request a partial read that only adds files representing #Main data (IDs). Used when
* #Main may have received changes of interest (e.g. asset removed or renamed). */
bool only_main_data;
/** Shallow copy of #filelist for thread-safe access.
*
* The job system calls #filelist_readjob_update which moves any read file from #tmp_filelist
* into #filelist in a thread-safe way.
*
* #tmp_filelist also keeps an `AssetLibrary *` so that it can be loaded in the same thread,
* and moved to #filelist once all categories are loaded.
*
* NOTE: #tmp_filelist is freed in #filelist_readjob_free, so any copied pointers need to be
* set to nullptr to avoid double-freeing them. */
FileList *tmp_filelist;
};
/**
* Append \a filename (or even a path inside of a .blend, like `Material/Material.001`), to the
* current relative path being read within the filelist root. The returned string needs freeing
* with #MEM_freeN().
*/
static char *current_relpath_append(const FileListReadJob *job_params, const char *filename)
{
const char *relbase = job_params->cur_relbase;
/* Early exit, nothing to join. */
if (!relbase[0]) {
return BLI_strdup(filename);
}
BLI_assert(relbase[strlen(relbase) - 1] == SEP);
BLI_assert(BLI_path_is_rel(relbase));
char relpath[FILE_MAX_LIBEXTRA];
/* Using #BLI_path_join works but isn't needed as `rel_subdir` has a trailing slash. */
BLI_string_join(relpath,
sizeof(relpath),
/* + 2 to remove "//" relative path prefix. */
relbase + 2,
filename);
return BLI_strdup(relpath);
}
static int filelist_readjob_list_dir(FileListReadJob *job_params,
const char *root,
ListBase *entries,
const char *filter_glob,
const bool do_lib,
@ -2928,7 +2997,7 @@ static int filelist_readjob_list_dir(const char *root,
}
entry = MEM_cnew<FileListInternEntry>(__func__);
entry->relpath = static_cast<char *>(MEM_dupallocN(files[i].relname));
entry->relpath = current_relpath_append(job_params, files[i].relname);
entry->st = files[i].s;
BLI_path_join(full_path, FILE_MAX, root, entry->relpath);
@ -3015,11 +3084,11 @@ enum ListLibOptions {
};
ENUM_OPERATORS(ListLibOptions, LIST_LIB_ADD_PARENT);
static FileListInternEntry *filelist_readjob_list_lib_group_create(const int idcode,
const char *group_name)
static FileListInternEntry *filelist_readjob_list_lib_group_create(
const FileListReadJob *job_params, const int idcode, const char *group_name)
{
FileListInternEntry *entry = MEM_cnew<FileListInternEntry>(__func__);
entry->relpath = BLI_strdup(group_name);
entry->relpath = current_relpath_append(job_params, group_name);
entry->typeflag |= FILE_TYPE_BLENDERLIB | FILE_TYPE_DIR;
entry->blentype = idcode;
return entry;
@ -3029,19 +3098,21 @@ static FileListInternEntry *filelist_readjob_list_lib_group_create(const int idc
* \warning: This "steals" the asset metadata from \a datablock_info. Not great design but fixing
* this requires redesigning things on the caller side for proper ownership management.
*/
static void filelist_readjob_list_lib_add_datablock(FileList *filelist,
static void filelist_readjob_list_lib_add_datablock(FileListReadJob *job_params,
ListBase *entries,
BLODataBlockInfo *datablock_info,
const bool prefix_relpath_with_group_name,
const int idcode,
const char *group_name)
{
FileList *filelist = job_params->tmp_filelist; /* Use the thread-safe filelist queue. */
FileListInternEntry *entry = MEM_cnew<FileListInternEntry>(__func__);
if (prefix_relpath_with_group_name) {
entry->relpath = BLI_sprintfN("%s/%s", group_name, datablock_info->name);
std::string datablock_path = StringRef(group_name) + "/" + datablock_info->name;
entry->relpath = current_relpath_append(job_params, datablock_path.c_str());
}
else {
entry->relpath = BLI_strdup(datablock_info->name);
entry->relpath = current_relpath_append(job_params, datablock_info->name);
}
entry->typeflag |= FILE_TYPE_BLENDERLIB;
if (datablock_info) {
@ -3056,8 +3127,8 @@ static void filelist_readjob_list_lib_add_datablock(FileList *filelist,
datablock_info->asset_data);
BKE_asset_metadata_free(&datablock_info->asset_data);
entry->asset = &filelist->asset_library->add_external_asset(datablock_info->name,
std::move(metadata));
entry->asset = &filelist->asset_library->add_external_asset(
entry->relpath, datablock_info->name, std::move(metadata));
}
}
}
@ -3065,7 +3136,7 @@ static void filelist_readjob_list_lib_add_datablock(FileList *filelist,
BLI_addtail(entries, entry);
}
static void filelist_readjob_list_lib_add_datablocks(FileList *filelist,
static void filelist_readjob_list_lib_add_datablocks(FileListReadJob *job_params,
ListBase *entries,
LinkNode *datablock_infos,
const bool prefix_relpath_with_group_name,
@ -3075,12 +3146,12 @@ static void filelist_readjob_list_lib_add_datablocks(FileList *filelist,
for (LinkNode *ln = datablock_infos; ln; ln = ln->next) {
struct BLODataBlockInfo *datablock_info = static_cast<BLODataBlockInfo *>(ln->link);
filelist_readjob_list_lib_add_datablock(
filelist, entries, datablock_info, prefix_relpath_with_group_name, idcode, group_name);
job_params, entries, datablock_info, prefix_relpath_with_group_name, idcode, group_name);
}
}
static void filelist_readjob_list_lib_add_from_indexer_entries(
FileList *filelist,
FileListReadJob *job_params,
ListBase *entries,
const FileIndexerEntries *indexer_entries,
const bool prefix_relpath_with_group_name)
@ -3088,7 +3159,7 @@ static void filelist_readjob_list_lib_add_from_indexer_entries(
for (const LinkNode *ln = indexer_entries->entries; ln; ln = ln->next) {
FileIndexerEntry *indexer_entry = static_cast<FileIndexerEntry *>(ln->link);
const char *group_name = BKE_idtype_idcode_to_name(indexer_entry->idcode);
filelist_readjob_list_lib_add_datablock(filelist,
filelist_readjob_list_lib_add_datablock(job_params,
entries,
&indexer_entry->datablock_info,
prefix_relpath_with_group_name,
@ -3097,10 +3168,11 @@ static void filelist_readjob_list_lib_add_from_indexer_entries(
}
}
static FileListInternEntry *filelist_readjob_list_lib_navigate_to_parent_entry_create(void)
static FileListInternEntry *filelist_readjob_list_lib_navigate_to_parent_entry_create(
const FileListReadJob *job_params)
{
FileListInternEntry *entry = MEM_cnew<FileListInternEntry>(__func__);
entry->relpath = BLI_strdup(FILENAME_PARENT);
entry->relpath = current_relpath_append(job_params, FILENAME_PARENT);
entry->typeflag |= (FILE_TYPE_BLENDERLIB | FILE_TYPE_DIR);
return entry;
}
@ -3117,7 +3189,7 @@ typedef struct FileIndexer {
void *user_data;
} FileIndexer;
static int filelist_readjob_list_lib_populate_from_index(FileList *filelist,
static int filelist_readjob_list_lib_populate_from_index(FileListReadJob *job_params,
ListBase *entries,
const ListLibOptions options,
const int read_from_index,
@ -3125,12 +3197,13 @@ static int filelist_readjob_list_lib_populate_from_index(FileList *filelist,
{
int navigate_to_parent_len = 0;
if (options & LIST_LIB_ADD_PARENT) {
FileListInternEntry *entry = filelist_readjob_list_lib_navigate_to_parent_entry_create();
FileListInternEntry *entry = filelist_readjob_list_lib_navigate_to_parent_entry_create(
job_params);
BLI_addtail(entries, entry);
navigate_to_parent_len = 1;
}
filelist_readjob_list_lib_add_from_indexer_entries(filelist, entries, indexer_entries, true);
filelist_readjob_list_lib_add_from_indexer_entries(job_params, entries, indexer_entries, true);
return read_from_index + navigate_to_parent_len;
}
@ -3138,7 +3211,7 @@ static int filelist_readjob_list_lib_populate_from_index(FileList *filelist,
* \return The number of entries found if the \a root path points to a valid library file.
* Otherwise returns no value (#std::nullopt).
*/
static std::optional<int> filelist_readjob_list_lib(FileList *filelist,
static std::optional<int> filelist_readjob_list_lib(FileListReadJob *job_params,
const char *root,
ListBase *entries,
const ListLibOptions options,
@ -3178,7 +3251,7 @@ static std::optional<int> filelist_readjob_list_lib(FileList *filelist,
dir, &indexer_entries, &read_from_index, indexer_runtime->user_data);
if (indexer_result == FILE_INDEXER_ENTRIES_LOADED) {
int entries_read = filelist_readjob_list_lib_populate_from_index(
filelist, entries, options, read_from_index, &indexer_entries);
job_params, entries, options, read_from_index, &indexer_entries);
ED_file_indexer_entries_clear(&indexer_entries);
return entries_read;
}
@ -3197,7 +3270,8 @@ static std::optional<int> filelist_readjob_list_lib(FileList *filelist,
* the code clean and readable and not counting in a single variable. */
int navigate_to_parent_len = 0;
if (options & LIST_LIB_ADD_PARENT) {
FileListInternEntry *entry = filelist_readjob_list_lib_navigate_to_parent_entry_create();
FileListInternEntry *entry = filelist_readjob_list_lib_navigate_to_parent_entry_create(
job_params);
BLI_addtail(entries, entry);
navigate_to_parent_len = 1;
}
@ -3209,7 +3283,7 @@ static std::optional<int> filelist_readjob_list_lib(FileList *filelist,
LinkNode *datablock_infos = BLO_blendhandle_get_datablock_info(
libfiledata, idcode, options & LIST_LIB_ASSETS_ONLY, &datablock_len);
filelist_readjob_list_lib_add_datablocks(
filelist, entries, datablock_infos, false, idcode, group);
job_params, entries, datablock_infos, false, idcode, group);
BLI_linklist_freeN(datablock_infos);
}
else {
@ -3219,8 +3293,8 @@ static std::optional<int> filelist_readjob_list_lib(FileList *filelist,
for (LinkNode *ln = groups; ln; ln = ln->next) {
const char *group_name = static_cast<char *>(ln->link);
const int idcode = groupname_to_code(group_name);
FileListInternEntry *group_entry = filelist_readjob_list_lib_group_create(idcode,
group_name);
FileListInternEntry *group_entry = filelist_readjob_list_lib_group_create(
job_params, idcode, group_name);
BLI_addtail(entries, group_entry);
if (options & LIST_LIB_RECURSIVE) {
@ -3228,7 +3302,7 @@ static std::optional<int> filelist_readjob_list_lib(FileList *filelist,
LinkNode *group_datablock_infos = BLO_blendhandle_get_datablock_info(
libfiledata, idcode, options & LIST_LIB_ASSETS_ONLY, &group_datablock_len);
filelist_readjob_list_lib_add_datablocks(
filelist, entries, group_datablock_infos, true, idcode, group_name);
job_params, entries, group_datablock_infos, true, idcode, group_name);
if (use_indexer) {
ED_file_indexer_entries_extend_from_datablock_infos(
&indexer_entries, group_datablock_infos, idcode);
@ -3427,28 +3501,6 @@ static void filelist_readjob_main_recursive(Main *bmain, FileList *filelist)
}
#endif
struct FileListReadJob {
ThreadMutex lock;
char main_name[FILE_MAX];
Main *current_main;
FileList *filelist;
/** Set to request a partial read that only adds files representing #Main data (IDs). Used when
* #Main may have received changes of interest (e.g. asset removed or renamed). */
bool only_main_data;
/** Shallow copy of #filelist for thread-safe access.
*
* The job system calls #filelist_readjob_update which moves any read file from #tmp_filelist
* into #filelist in a thread-safe way.
*
* #tmp_filelist also keeps an `AssetLibrary *` so that it can be loaded in the same thread,
* and moved to #filelist once all categories are loaded.
*
* NOTE: #tmp_filelist is freed in #filelist_readjob_free, so any copied pointers need to be
* set to nullptr to avoid double-freeing them. */
FileList *tmp_filelist;
};
static void filelist_readjob_append_entries(FileListReadJob *job_params,
ListBase *from_entries,
int from_entries_num,
@ -3562,6 +3614,9 @@ static void filelist_readjob_recursive_dir_add_items(const bool do_lib,
BLI_path_normalize_dir(root, rel_subdir, sizeof(rel_subdir));
BLI_path_rel(rel_subdir, root);
/* Update the current relative base path within the filelist root. */
BLI_strncpy(job_params->cur_relbase, rel_subdir, sizeof(job_params->cur_relbase));
bool is_lib = false;
if (do_lib) {
ListLibOptions list_lib_options = LIST_LIB_OPTION_NONE;
@ -3580,7 +3635,7 @@ static void filelist_readjob_recursive_dir_add_items(const bool do_lib,
list_lib_options |= LIST_LIB_ASSETS_ONLY;
}
std::optional<int> lib_entries_num = filelist_readjob_list_lib(
filelist, subdir, &entries, list_lib_options, &indexer_runtime);
job_params, subdir, &entries, list_lib_options, &indexer_runtime);
if (lib_entries_num) {
is_lib = true;
entries_num += *lib_entries_num;
@ -3589,19 +3644,11 @@ static void filelist_readjob_recursive_dir_add_items(const bool do_lib,
if (!is_lib && BLI_is_dir(subdir)) {
entries_num = filelist_readjob_list_dir(
subdir, &entries, filter_glob, do_lib, job_params->main_name, skip_currpar);
job_params, subdir, &entries, filter_glob, do_lib, job_params->main_name, skip_currpar);
}
LISTBASE_FOREACH (FileListInternEntry *, entry, &entries) {
entry->uid = filelist_uid_generate(filelist);
/* When loading entries recursive, the `rel_path` should be relative from the root dir.
* we combine the relative path to the `subdir` with the relative path of the entry.
* Using #BLI_path_join works but isn't needed as `rel_subdir` has a trailing slash. */
BLI_string_join(dir, sizeof(dir), rel_subdir, entry->relpath);
MEM_freeN(entry->relpath);
entry->relpath = BLI_strdup(dir + 2); /* + 2 to remove '//'
* added by BLI_path_rel to rel_subdir. */
entry->name = fileentry_uiname(root, entry, dir);
entry->free_name = true;
@ -3726,7 +3773,8 @@ static void filelist_readjob_main_assets_add_items(FileListReadJob *job_params,
const char *id_code_name = BKE_idtype_idcode_to_name(GS(id_iter->name));
entry = MEM_cnew<FileListInternEntry>(__func__);
entry->relpath = BLI_strdup(id_code_name);
std::string datablock_path = StringRef(id_code_name) + "/" + (id_iter->name + 2);
entry->relpath = current_relpath_append(job_params, datablock_path.c_str());
entry->name = id_iter->name + 2;
entry->free_name = false;
entry->typeflag |= FILE_TYPE_BLENDERLIB | FILE_TYPE_ASSET;
@ -3736,7 +3784,7 @@ static void filelist_readjob_main_assets_add_items(FileListReadJob *job_params,
id_iter);
entry->local_data.id = id_iter;
if (filelist->asset_library) {
entry->asset = &filelist->asset_library->add_local_id_asset(*id_iter);
entry->asset = &filelist->asset_library->add_local_id_asset(entry->relpath, *id_iter);
}
entries_num++;
BLI_addtail(&tmp_entries, entry);

View File

@ -71,6 +71,9 @@ void filelist_setlibrary(struct FileList *filelist,
void filelist_init_icons(void);
void filelist_free_icons(void);
void filelist_file_get_full_path(const struct FileList *filelist,
const FileDirEntry *file,
char r_path[/*FILE_MAX_LIBEXTRA*/]);
struct ImBuf *filelist_getimage(struct FileList *filelist, int index);
struct ImBuf *filelist_file_getimage(const FileDirEntry *file);
struct ImBuf *filelist_geticon_image_ex(const FileDirEntry *file);
@ -91,7 +94,7 @@ void filelist_clear_ex(struct FileList *filelist,
void filelist_clear_from_reset_tag(struct FileList *filelist);
void filelist_free(struct FileList *filelist);
const char *filelist_dir(struct FileList *filelist);
const char *filelist_dir(const struct FileList *filelist);
bool filelist_is_dir(struct FileList *filelist, const char *path);
/**
* May modify in place given r_dir, which is expected to be FILE_MAX_LIBEXTRA length.

View File

@ -67,7 +67,6 @@ static void add_node_search_listen_fn(const wmRegionListenerParams *params, void
}
static void search_items_for_asset_metadata(const bNodeTree &node_tree,
const AssetLibraryReference &library_ref,
const AssetHandle asset,
Vector<AddNodeItem> &search_items)
{
@ -82,10 +81,10 @@ static void search_items_for_asset_metadata(const bNodeTree &node_tree,
item.identifier = node_tree.typeinfo->group_idname;
item.description = asset_data.description == nullptr ? "" : asset_data.description;
item.asset = asset;
item.after_add_fn = [asset, library_ref](const bContext &C, bNodeTree &node_tree, bNode &node) {
item.after_add_fn = [asset](const bContext &C, bNodeTree &node_tree, bNode &node) {
Main &bmain = *CTX_data_main(&C);
node.flag &= ~NODE_OPTIONS;
node.id = asset::get_local_id_from_asset_or_append_and_reuse(bmain, library_ref, asset);
node.id = asset::get_local_id_from_asset_or_append_and_reuse(bmain, asset);
id_us_plus(node.id);
BKE_ntree_update_tag_node_property(&node_tree, &node);
DEG_relations_tag_update(&bmain);
@ -113,7 +112,7 @@ static void gather_search_items_for_asset_library(const bContext &C,
/* If an asset with the same name has already been added, skip this. */
return true;
}
search_items_for_asset_metadata(node_tree, library_ref, asset, search_items);
search_items_for_asset_metadata(node_tree, asset, search_items);
return true;
});
}

View File

@ -141,7 +141,6 @@ static void add_existing_group_input_fn(nodes::LinkSearchOpParams &params,
*/
static void search_link_ops_for_asset_metadata(const bNodeTree &node_tree,
const bNodeSocket &socket,
const AssetLibraryReference &library_ref,
const AssetHandle asset,
Vector<SocketLinkOperation> &search_link_ops)
{
@ -186,13 +185,13 @@ static void search_link_ops_for_asset_metadata(const bNodeTree &node_tree,
search_link_ops.append(
{asset_name + " " + UI_MENU_ARROW_SEP + socket_name,
[library_ref, asset, socket_property, in_out](nodes::LinkSearchOpParams &params) {
[asset, socket_property, in_out](nodes::LinkSearchOpParams &params) {
Main &bmain = *CTX_data_main(&params.C);
bNode &node = params.add_node(params.node_tree.typeinfo->group_idname);
node.flag &= ~NODE_OPTIONS;
node.id = asset::get_local_id_from_asset_or_append_and_reuse(bmain, library_ref, asset);
node.id = asset::get_local_id_from_asset_or_append_and_reuse(bmain, asset);
id_us_plus(node.id);
BKE_ntree_update_tag_node_property(&params.node_tree, &node);
DEG_relations_tag_update(&bmain);
@ -232,7 +231,7 @@ static void gather_search_link_ops_for_asset_library(const bContext &C,
if (skip_local && ED_asset_handle_get_local_id(&asset) != nullptr) {
return true;
}
search_link_ops_for_asset_metadata(node_tree, socket, library_ref, asset, search_link_ops);
search_link_ops_for_asset_metadata(node_tree, socket, asset, search_link_ops);
return true;
});
}

View File

@ -372,17 +372,14 @@ void NODE_OT_add_group(wmOperatorType *ot)
/** \name Add Node Group Asset Operator
* \{ */
static bool add_node_group_asset(const bContext &C,
const AssetLibraryReference &library_ref,
const AssetHandle asset,
ReportList &reports)
static bool add_node_group_asset(const bContext &C, const AssetHandle asset, ReportList &reports)
{
Main &bmain = *CTX_data_main(&C);
SpaceNode &snode = *CTX_wm_space_node(&C);
bNodeTree &edit_tree = *snode.edittree;
bNodeTree *node_group = reinterpret_cast<bNodeTree *>(
asset::get_local_id_from_asset_or_append_and_reuse(bmain, library_ref, asset));
asset::get_local_id_from_asset_or_append_and_reuse(bmain, asset));
if (!node_group) {
return false;
}
@ -439,7 +436,7 @@ static int node_add_group_asset_invoke(bContext *C, wmOperator *op, const wmEven
snode.runtime->cursor /= UI_DPI_FAC;
if (!add_node_group_asset(*C, *library_ref, handle, *op->reports)) {
if (!add_node_group_asset(*C, handle, *op->reports)) {
return OPERATOR_CANCELLED;
}

View File

@ -2793,18 +2793,19 @@ static bool node_shader_script_update_poll(bContext *C)
static bool node_shader_script_update_text_recursive(RenderEngine *engine,
RenderEngineType *type,
bNodeTree *ntree,
Text *text)
Text *text,
Set<bNodeTree *> &done_trees)
{
bool found = false;
ntree->runtime->done = true;
done_trees.add_new(ntree);
/* update each script that is using this text datablock */
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type == NODE_GROUP) {
bNodeTree *ngroup = (bNodeTree *)node->id;
if (ngroup && !ngroup->runtime->done) {
found |= node_shader_script_update_text_recursive(engine, type, ngroup, text);
if (ngroup && !done_trees.contains(ngroup)) {
found |= node_shader_script_update_text_recursive(engine, type, ngroup, text, done_trees);
}
}
else if (node->type == SH_NODE_SCRIPT && node->id == &text->id) {
@ -2852,18 +2853,14 @@ static int node_shader_script_update_exec(bContext *C, wmOperator *op)
Text *text = (Text *)CTX_data_pointer_get_type(C, "edit_text", &RNA_Text).data;
if (text) {
/* clear flags for recursion check */
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
if (ntree->type == NTREE_SHADER) {
ntree->runtime->done = false;
}
}
FOREACH_NODETREE_END;
Set<bNodeTree *> done_trees;
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
if (ntree->type == NTREE_SHADER) {
if (!ntree->runtime->done) {
found |= node_shader_script_update_text_recursive(engine, type, ntree, text);
if (!done_trees.contains(ntree)) {
found |= node_shader_script_update_text_recursive(
engine, type, ntree, text, done_trees);
}
}
}

View File

@ -902,8 +902,6 @@ static void node_link_exit(bContext &C, wmOperator &op, const bool apply_links)
bNodeTree &ntree = *snode.edittree;
bNodeLinkDrag *nldrag = (bNodeLinkDrag *)op.customdata;
/* avoid updates while applying links */
ntree.runtime->is_updating = true;
for (bNodeLink *link : nldrag->links) {
link->flag &= ~NODE_LINK_DRAGGED;
@ -929,7 +927,6 @@ static void node_link_exit(bContext &C, wmOperator &op, const bool apply_links)
nodeRemLink(&ntree, link);
}
}
ntree.runtime->is_updating = false;
ED_node_tree_propagate_change(&C, bmain, &ntree);

View File

@ -285,7 +285,7 @@ static void sequencer_drop_copy(bContext *C, wmDrag *drag, wmDropBox *drop)
/* We are dropped inside the preview region. Put the strip on top of the
* current displayed frame. */
Scene *scene = CTX_data_scene(C);
Editing *ed = SEQ_editing_get(scene);
Editing *ed = SEQ_editing_ensure(scene);
ListBase *seqbase = SEQ_active_seqbase_get(ed);
ListBase *channels = SEQ_channels_displayed_get(ed);
SpaceSeq *sseq = CTX_wm_space_seq(C);

View File

@ -565,7 +565,7 @@ static void sequencer_main_clamp_view(const bContext *C, ARegion *region)
/* Initialize default view with 7 channels, that are visible even if empty. */
rctf strip_boundbox;
BLI_rctf_init(&strip_boundbox, 0.0f, 0.0f, 1.0f, 7.0f);
BLI_rctf_init(&strip_boundbox, 0.0f, 0.0f, 1.0f, 6.0f);
SEQ_timeline_expand_boundbox(scene, ed->seqbasep, &strip_boundbox);
/* Clamp Y max. Scrubbing area height must be added, so strips aren't occluded. */
@ -574,8 +574,8 @@ static void sequencer_main_clamp_view(const bContext *C, ARegion *region)
const float pixel_view_size_y = BLI_rctf_size_y(&v2d->cur) / BLI_rcti_size_y(&v2d->mask);
const float scrub_bar_height = BLI_rcti_size_y(&scrub_rect) * pixel_view_size_y;
/* Channel n has range of <n, n+1>. */
strip_boundbox.ymax += 1.0f + scrub_bar_height;
/* Channel n has range of <n, n+1>, +1 for empty channel. */
strip_boundbox.ymax += 2.0f + scrub_bar_height;
/* Clamp Y min. Scroller and marker area height must be added, so strips aren't occluded. */
float scroll_bar_height = v2d->hor.ymax * pixel_view_size_y;

View File

@ -297,17 +297,6 @@ static PHashLink *phash_next(PHash *ph, PHashKey key, PHashLink *link)
return link;
}
/* Geometry */
static float p_vec_angle(const float v1[3], const float v2[3], const float v3[3])
{
return angle_v3v3v3(v1, v2, v3);
}
static float p_vec2_angle(const float v1[2], const float v2[2], const float v3[2])
{
return angle_v2v2v2(v1, v2, v3);
}
/* Angles close to 0 or 180 degrees cause rows filled with zeros in the linear_solver.
* The matrix will then be rank deficient and / or have poor conditioning.
* => Reduce the maximum angle to 179 degrees, and spread the remainder to the other angles.
@ -358,9 +347,9 @@ static void fix_large_angle(const float v_fix[3],
static void p_triangle_angles(
const float v1[3], const float v2[3], const float v3[3], float *r_a1, float *r_a2, float *r_a3)
{
*r_a1 = p_vec_angle(v3, v1, v2);
*r_a2 = p_vec_angle(v1, v2, v3);
*r_a3 = p_vec_angle(v2, v3, v1);
*r_a1 = angle_v3v3v3(v3, v1, v2);
*r_a2 = angle_v3v3v3(v1, v2, v3);
*r_a3 = angle_v3v3v3(v2, v3, v1);
/* Fix for degenerate geometry e.g. v1 = sum(v2 + v3). See T100874 */
fix_large_angle(v1, v2, v3, r_a1, r_a2, r_a3);
@ -437,9 +426,7 @@ static float p_chart_uv_area(PChart *chart)
static void p_chart_uv_scale(PChart *chart, float scale)
{
PVert *v;
for (v = chart->verts; v; v = v->nextlink) {
for (PVert *v = chart->verts; v; v = v->nextlink) {
v->uv[0] *= scale;
v->uv[1] *= scale;
}
@ -447,9 +434,7 @@ static void p_chart_uv_scale(PChart *chart, float scale)
static void p_chart_uv_scale_xy(PChart *chart, float x, float y)
{
PVert *v;
for (v = chart->verts; v; v = v->nextlink) {
for (PVert *v = chart->verts; v; v = v->nextlink) {
v->uv[0] *= x;
v->uv[1] *= y;
}
@ -457,9 +442,7 @@ static void p_chart_uv_scale_xy(PChart *chart, float x, float y)
static void p_chart_uv_translate(PChart *chart, const float trans[2])
{
PVert *v;
for (v = chart->verts; v; v = v->nextlink) {
for (PVert *v = chart->verts; v; v = v->nextlink) {
v->uv[0] += trans[0];
v->uv[1] += trans[1];
}
@ -467,9 +450,7 @@ static void p_chart_uv_translate(PChart *chart, const float trans[2])
static void p_chart_uv_transform(PChart *chart, const float mat[2][2])
{
PVert *v;
for (v = chart->verts; v; v = v->nextlink) {
for (PVert *v = chart->verts; v; v = v->nextlink) {
mul_m2_v2(mat, v->uv);
}
}
@ -628,25 +609,18 @@ static void p_vert_load_pin_select_uvs(ParamHandle *handle, PVert *v)
static void p_flush_uvs(ParamHandle *handle, PChart *chart)
{
PEdge *e;
for (e = chart->edges; e; e = e->nextlink) {
const float blend = handle->blend;
const float invblend = 1.0f - blend;
for (PEdge *e = chart->edges; e; e = e->nextlink) {
if (e->orig_uv) {
e->orig_uv[0] = e->vert->uv[0] / handle->aspx;
e->orig_uv[1] = e->vert->uv[1] / handle->aspy;
}
}
}
static void p_flush_uvs_blend(ParamHandle *handle, PChart *chart, float blend)
{
PEdge *e;
float invblend = 1.0f - blend;
for (e = chart->edges; e; e = e->nextlink) {
if (e->orig_uv) {
e->orig_uv[0] = blend * e->old_uv[0] + invblend * e->vert->uv[0] / handle->aspx;
e->orig_uv[1] = blend * e->old_uv[1] + invblend * e->vert->uv[1] / handle->aspy;
if (blend) {
e->orig_uv[0] = blend * e->old_uv[0] + invblend * e->vert->uv[0] / handle->aspx;
e->orig_uv[1] = blend * e->old_uv[1] + invblend * e->vert->uv[1] / handle->aspy;
}
else {
e->orig_uv[0] = e->vert->uv[0] / handle->aspx;
e->orig_uv[1] = e->vert->uv[1] / handle->aspy;
}
}
}
}
@ -1229,7 +1203,7 @@ static float p_edge_boundary_angle(PEdge *e)
do {
v1 = we->next->vert;
v2 = we->next->next->vert;
angle -= p_vec_angle(v1->co, v->co, v2->co);
angle -= angle_v3v3v3(v1->co, v->co, v2->co);
we = we->next->next->pair;
n++;
@ -3113,29 +3087,21 @@ static void p_chart_lscm_begin(PChart *chart, bool live, bool abf)
static bool p_chart_lscm_solve(ParamHandle *handle, PChart *chart)
{
LinearSolver *context = chart->u.lscm.context;
PVert *v, *pin1 = chart->u.lscm.pin1, *pin2 = chart->u.lscm.pin2;
PFace *f;
const float *alpha = chart->u.lscm.abf_alpha;
float area_pinned_up, area_pinned_down;
bool flip_faces;
int row;
#if 0
/* TODO: make loading pins work for simplify/complexify. */
#endif
for (v = chart->verts; v; v = v->nextlink) {
for (PVert *v = chart->verts; v; v = v->nextlink) {
if (v->flag & PVERT_PIN) {
p_vert_load_pin_select_uvs(handle, v); /* reload for live */
p_vert_load_pin_select_uvs(handle, v); /* Reload for Live Unwrap. */
}
}
if (chart->u.lscm.single_pin) {
/* If only one pin, save area and pin for transform later. */
/* If only one pin, save pin location for transform later. */
copy_v2_v2(chart->u.lscm.single_pin_uv, chart->u.lscm.single_pin->uv);
}
if (chart->u.lscm.pin1) {
PVert *pin1 = chart->u.lscm.pin1;
PVert *pin2 = chart->u.lscm.pin2;
EIG_linear_solver_variable_lock(context, 2 * pin1->u.id);
EIG_linear_solver_variable_lock(context, 2 * pin1->u.id + 1);
EIG_linear_solver_variable_lock(context, 2 * pin2->u.id);
@ -3147,8 +3113,8 @@ static bool p_chart_lscm_solve(ParamHandle *handle, PChart *chart)
EIG_linear_solver_variable_set(context, 0, 2 * pin2->u.id + 1, pin2->uv[1]);
}
else {
/* set and lock the pins */
for (v = chart->verts; v; v = v->nextlink) {
/* Set and lock the pins. */
for (PVert *v = chart->verts; v; v = v->nextlink) {
if (v->flag & PVERT_PIN) {
EIG_linear_solver_variable_lock(context, 2 * v->u.id);
EIG_linear_solver_variable_lock(context, 2 * v->u.id + 1);
@ -3159,16 +3125,16 @@ static bool p_chart_lscm_solve(ParamHandle *handle, PChart *chart)
}
}
/* detect up direction based on pinned vertices */
area_pinned_up = 0.0f;
area_pinned_down = 0.0f;
/* Detect "up" direction based on pinned vertices. */
float area_pinned_up = 0.0f;
float area_pinned_down = 0.0f;
for (f = chart->faces; f; f = f->nextlink) {
for (PFace *f = chart->faces; f; f = f->nextlink) {
PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
if ((v1->flag & PVERT_PIN) && (v2->flag & PVERT_PIN) && (v3->flag & PVERT_PIN)) {
float area = p_face_uv_area_signed(f);
const float area = p_face_uv_area_signed(f);
if (area > 0.0f) {
area_pinned_up += area;
@ -3179,19 +3145,18 @@ static bool p_chart_lscm_solve(ParamHandle *handle, PChart *chart)
}
}
flip_faces = (area_pinned_down > area_pinned_up);
const bool flip_faces = (area_pinned_down > area_pinned_up);
/* construct matrix */
row = 0;
for (f = chart->faces; f; f = f->nextlink) {
/* Construct matrix. */
const float *alpha = chart->u.lscm.abf_alpha;
int row = 0;
for (PFace *f = chart->faces; f; f = f->nextlink) {
PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
float a1, a2, a3, ratio, cosine, sine;
float sina1, sina2, sina3, sinmax;
float a1, a2, a3;
if (alpha) {
/* use abf angles if passed on */
/* Use abf angles if present. */
a1 = *(alpha++);
a2 = *(alpha++);
a3 = *(alpha++);
@ -3206,13 +3171,13 @@ static bool p_chart_lscm_solve(ParamHandle *handle, PChart *chart)
SWAP(PVert *, v2, v3);
}
sina1 = sinf(a1);
sina2 = sinf(a2);
sina3 = sinf(a3);
float sina1 = sinf(a1);
float sina2 = sinf(a2);
float sina3 = sinf(a3);
sinmax = max_fff(sina1, sina2, sina3);
const float sinmax = max_fff(sina1, sina2, sina3);
/* shift vertices to find most stable order */
/* Shift vertices to find most stable order. */
if (sina3 != sinmax) {
SHIFT3(PVert *, v1, v2, v3);
SHIFT3(float, a1, a2, a3);
@ -3225,10 +3190,10 @@ static bool p_chart_lscm_solve(ParamHandle *handle, PChart *chart)
}
}
/* angle based lscm formulation */
ratio = (sina3 == 0.0f) ? 1.0f : sina2 / sina3;
cosine = cosf(a1) * ratio;
sine = sina1 * ratio;
/* Angle based lscm formulation. */
const float ratio = (sina3 == 0.0f) ? 1.0f : sina2 / sina3;
const float cosine = cosf(a1) * ratio;
const float sine = sina1 * ratio;
EIG_linear_solver_matrix_add(context, row, 2 * v1->u.id, cosine - 1.0f);
EIG_linear_solver_matrix_add(context, row, 2 * v1->u.id + 1, -sine);
@ -3250,7 +3215,7 @@ static bool p_chart_lscm_solve(ParamHandle *handle, PChart *chart)
return true;
}
for (v = chart->verts; v; v = v->nextlink) {
for (PVert *v = chart->verts; v; v = v->nextlink) {
v->uv[0] = 0.0f;
v->uv[1] = 0.0f;
}
@ -3588,7 +3553,7 @@ static float p_chart_minimum_area_angle(PChart *chart)
p2 = points[i];
p3 = (i == npoints - 1) ? points[0] : points[i + 1];
angles[i] = float(M_PI) - p_vec2_angle(p1->uv, p2->uv, p3->uv);
angles[i] = float(M_PI) - angle_v2v2v2(p1->uv, p2->uv, p3->uv);
if (points[i]->uv[1] < miny) {
miny = points[i]->uv[1];
@ -3608,19 +3573,19 @@ static float p_chart_minimum_area_angle(PChart *chart)
v[0] = points[idx[0]]->uv[0];
v[1] = points[idx[0]]->uv[1] + 1.0f;
a[0] = p_vec2_angle(points[(idx[0] + 1) % npoints]->uv, points[idx[0]]->uv, v);
a[0] = angle_v2v2v2(points[(idx[0] + 1) % npoints]->uv, points[idx[0]]->uv, v);
v[0] = points[idx[1]]->uv[0] + 1.0f;
v[1] = points[idx[1]]->uv[1];
a[1] = p_vec2_angle(points[(idx[1] + 1) % npoints]->uv, points[idx[1]]->uv, v);
a[1] = angle_v2v2v2(points[(idx[1] + 1) % npoints]->uv, points[idx[1]]->uv, v);
v[0] = points[idx[2]]->uv[0];
v[1] = points[idx[2]]->uv[1] - 1.0f;
a[2] = p_vec2_angle(points[(idx[2] + 1) % npoints]->uv, points[idx[2]]->uv, v);
a[2] = angle_v2v2v2(points[(idx[2] + 1) % npoints]->uv, points[idx[2]]->uv, v);
v[0] = points[idx[3]]->uv[0] - 1.0f;
v[1] = points[idx[3]]->uv[1];
a[3] = p_vec2_angle(points[(idx[3] + 1) % npoints]->uv, points[idx[3]]->uv, v);
a[3] = angle_v2v2v2(points[(idx[3] + 1) % npoints]->uv, points[idx[3]]->uv, v);
/* 4 rotating calipers */
@ -4018,14 +3983,11 @@ void GEO_uv_parametrizer_construct_end(ParamHandle *phandle,
void GEO_uv_parametrizer_lscm_begin(ParamHandle *phandle, bool live, bool abf)
{
PFace *f;
int i;
param_assert(phandle->state == PHANDLE_STATE_CONSTRUCTED);
phandle->state = PHANDLE_STATE_LSCM;
for (i = 0; i < phandle->ncharts; i++) {
for (f = phandle->charts[i]->faces; f; f = f->nextlink) {
for (int i = 0; i < phandle->ncharts; i++) {
for (PFace *f = phandle->charts[i]->faces; f; f = f->nextlink) {
p_face_backup_uvs(f);
}
p_chart_lscm_begin(phandle->charts[i], live, abf);
@ -4034,13 +3996,10 @@ void GEO_uv_parametrizer_lscm_begin(ParamHandle *phandle, bool live, bool abf)
void GEO_uv_parametrizer_lscm_solve(ParamHandle *phandle, int *count_changed, int *count_failed)
{
PChart *chart;
int i;
param_assert(phandle->state == PHANDLE_STATE_LSCM);
for (i = 0; i < phandle->ncharts; i++) {
chart = phandle->charts[i];
for (int i = 0; i < phandle->ncharts; i++) {
PChart *chart = phandle->charts[i];
if (chart->u.lscm.context) {
const bool result = p_chart_lscm_solve(phandle, chart);
@ -4427,12 +4386,7 @@ void GEO_uv_parametrizer_flush(ParamHandle *phandle)
continue;
}
if (phandle->blend == 0.0f) {
p_flush_uvs(phandle, chart);
}
else {
p_flush_uvs_blend(phandle, chart, phandle->blend);
}
p_flush_uvs(phandle, chart);
}
}

View File

@ -3,8 +3,6 @@
/** \file
* \ingroup obj
*/
/* Silence warnings from copying deprecated fields. Needed for an Object copy constructor use. */
#define DNA_DEPRECATED_ALLOW
#include "BKE_attribute.hh"
#include "BKE_customdata.h"
@ -101,9 +99,8 @@ std::pair<Mesh *, bool> OBJMesh::triangulate_mesh_eval()
* triangulated here. */
const int triangulate_min_verts = 4;
unique_bmesh_ptr bmesh(
BKE_mesh_to_bmesh_ex(export_mesh_eval_, &bm_create_params, &bm_convert_params));
BM_mesh_triangulate(bmesh.get(),
BMesh *bmesh = BKE_mesh_to_bmesh_ex(export_mesh_eval_, &bm_create_params, &bm_convert_params);
BM_mesh_triangulate(bmesh,
MOD_TRIANGULATE_NGON_BEAUTY,
MOD_TRIANGULATE_QUAD_SHORTEDGE,
triangulate_min_verts,
@ -112,8 +109,8 @@ std::pair<Mesh *, bool> OBJMesh::triangulate_mesh_eval()
nullptr,
nullptr);
Mesh *triangulated = BKE_mesh_from_bmesh_for_eval_nomain(
bmesh.get(), nullptr, export_mesh_eval_);
Mesh *triangulated = BKE_mesh_from_bmesh_for_eval_nomain(bmesh, nullptr, export_mesh_eval_);
BM_mesh_free(bmesh);
free_mesh_if_needed();
return {triangulated, true};
}

View File

@ -28,20 +28,6 @@ const int NOT_FOUND = -1;
/** Any negative number other than `NOT_FOUND` to initialize usually non-negative numbers. */
const int NEGATIVE_INIT = -10;
/**
* #std::unique_ptr than handles freeing #BMesh.
*/
struct CustomBMeshDeleter {
void operator()(BMesh *bmesh)
{
if (bmesh) {
BM_mesh_free(bmesh);
}
}
};
using unique_bmesh_ptr = std::unique_ptr<BMesh, CustomBMeshDeleter>;
class OBJMesh : NonCopyable {
private:
/**

View File

@ -273,13 +273,12 @@ static void rna_AssetHandle_file_data_set(PointerRNA *ptr,
static void rna_AssetHandle_get_full_library_path(
// AssetHandle *asset,
bContext *C,
FileDirEntry *asset_file,
AssetLibraryReference *library,
AssetLibraryReference *UNUSED(asset_library), /* Deprecated. */
char r_result[/*FILE_MAX_LIBEXTRA*/])
{
AssetHandle asset = {.file_data = asset_file};
ED_asset_handle_get_full_library_path(C, library, &asset, r_result);
ED_asset_handle_get_full_library_path(&asset, r_result);
}
static PointerRNA rna_AssetHandle_local_id_get(PointerRNA *ptr)
@ -424,19 +423,18 @@ static void rna_def_asset_handle_api(StructRNA *srna)
PropertyRNA *parm;
func = RNA_def_function(srna, "get_full_library_path", "rna_AssetHandle_get_full_library_path");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
/* TODO temporarily static function, for until .py can receive the asset handle from context
* properly. `asset_file_handle` should go away too then. */
RNA_def_function_flag(func, FUNC_NO_SELF);
parm = RNA_def_pointer(func, "asset_file_handle", "FileSelectEntry", "", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func,
"asset_library_ref",
"AssetLibraryReference",
"",
"The asset library containing the given asset, only valid if the asset "
"library is external (i.e. not the \"Current File\" one");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_pointer(
func,
"asset_library_ref",
"AssetLibraryReference",
"",
"The asset library containing the given asset. Deprecated and optional argument, will be "
"ignored. Kept for API compatibility only.");
parm = RNA_def_string(func, "result", NULL, FILE_MAX_LIBEXTRA, "result", "");
RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_function_output(func, parm);

View File

@ -143,7 +143,9 @@ static void node_geo_exec(GeoNodeExecParams params)
GeometryComponent &component = geometry_set.get_component_for_write(
GEO_COMPONENT_TYPE_INSTANCES);
if (!bke::try_capture_field_on_geometry(component, name, domain, field)) {
failure.store(true);
if (component.attribute_domain_size(domain) != 0) {
failure.store(true);
}
}
}
}
@ -154,7 +156,9 @@ static void node_geo_exec(GeoNodeExecParams params)
if (geometry_set.has(type)) {
GeometryComponent &component = geometry_set.get_component_for_write(type);
if (!bke::try_capture_field_on_geometry(component, name, domain, field)) {
failure.store(true);
if (component.attribute_domain_size(domain) != 0) {
failure.store(true);
}
}
}
}

View File

@ -102,7 +102,9 @@ bool nodeGroupPoll(const bNodeTree *nodetree,
return false;
}
if (nodetree->type != grouptree->type) {
*r_disabled_hint = TIP_("Node group has different type");
if (r_disabled_hint) {
*r_disabled_hint = TIP_("Node group has different type");
}
return false;
}

View File

@ -51,16 +51,72 @@ struct PyC_StringEnumItems bpygpu_dataformat_items[] = {
/** \name Utilities
* \{ */
bool bpygpu_is_init_or_error(void)
{
if (!GPU_is_init()) {
PyErr_SetString(PyExc_SystemError,
"GPU functions for drawing are not available in background mode");
static const char g_error[] = "GPU API is not available in background mode";
return false;
static PyObject *py_error__ml_meth(PyObject *UNUSED(self), PyObject *UNUSED(args))
{
PyErr_SetString(PyExc_SystemError, g_error);
return NULL;
}
static PyObject *py_error__getter(PyObject *UNUSED(self), void *UNUSED(type))
{
PyErr_SetString(PyExc_SystemError, g_error);
return NULL;
}
static int py_error__setter(PyObject *UNUSED(self), PyObject *UNUSED(value), void *UNUSED(type))
{
PyErr_SetString(PyExc_SystemError, g_error);
return -1;
}
static PyObject *py_error__tp_new(PyTypeObject *UNUSED(type),
PyObject *UNUSED(args),
PyObject *UNUSED(kwds))
{
PyErr_SetString(PyExc_SystemError, g_error);
return NULL;
}
PyObject *bpygpu_create_module(PyModuleDef *module_type)
{
if (!GPU_is_init() && module_type->m_methods) {
/* Replace all methods with an error method.
* That way when the method is called, an error will appear instead. */
for (PyMethodDef *meth = module_type->m_methods; meth->ml_name; meth++) {
meth->ml_meth = py_error__ml_meth;
}
}
return true;
PyObject *module = PyModule_Create(module_type);
return module;
}
int bpygpu_finalize_type(PyTypeObject *py_type)
{
if (!GPU_is_init()) {
if (py_type->tp_methods) {
/* Replace all methods with an error method. */
for (PyMethodDef *meth = py_type->tp_methods; meth->ml_name; meth++) {
meth->ml_meth = py_error__ml_meth;
}
}
if (py_type->tp_getset) {
/* Replace all getters and setter with a functions that always returns error. */
for (PyGetSetDef *getset = py_type->tp_getset; getset->name; getset++) {
getset->get = py_error__getter;
getset->set = py_error__setter;
}
}
if (py_type->tp_new) {
/* If initialized, return error. */
py_type->tp_new = py_error__tp_new;
}
}
return PyType_Ready(py_type);
}
/** \} */

View File

@ -6,18 +6,10 @@
#pragma once
#include "../generic/py_capi_utils.h"
extern struct PyC_StringEnumItems bpygpu_primtype_items[];
extern struct PyC_StringEnumItems bpygpu_dataformat_items[];
bool bpygpu_is_init_or_error(void);
#define BPYGPU_IS_INIT_OR_ERROR_OBJ \
if (UNLIKELY(!bpygpu_is_init_or_error())) { \
return NULL; \
} \
((void)0)
#define BPYGPU_IS_INIT_OR_ERROR_INT \
if (UNLIKELY(!bpygpu_is_init_or_error())) { \
return -1; \
} \
((void)0)
PyObject *bpygpu_create_module(PyModuleDef *module_type);
int bpygpu_finalize_type(PyTypeObject *py_type);

View File

@ -21,6 +21,7 @@
#include "gpu_py_state.h"
#include "gpu_py_types.h"
#include "gpu_py.h"
#include "gpu_py_api.h" /* Own include. */
/* -------------------------------------------------------------------- */
@ -48,7 +49,7 @@ PyObject *BPyInit_gpu(void)
PyObject *submodule;
PyObject *mod;
mod = PyModule_Create(&pygpu_module_def);
mod = bpygpu_create_module(&pygpu_module_def);
PyModule_AddObject(mod, "types", (submodule = bpygpu_types_init()));
PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);

View File

@ -47,8 +47,6 @@ static bool pygpu_batch_is_program_or_error(BPyGPUBatch *self)
static PyObject *pygpu_batch__tp_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds)
{
BPYGPU_IS_INIT_OR_ERROR_OBJ;
const char *exc_str_missing_arg = "GPUBatch.__new__() missing required argument '%s' (pos %d)";
struct PyC_StringEnum prim_type = {bpygpu_primtype_items, GPU_PRIM_NONE};

View File

@ -13,6 +13,7 @@
#include "GPU_capabilities.h"
#include "gpu_py.h"
#include "gpu_py_capabilities.h" /* own include */
/* -------------------------------------------------------------------- */
@ -315,7 +316,7 @@ PyObject *bpygpu_capabilities_init(void)
{
PyObject *submodule;
submodule = PyModule_Create(&pygpu_capabilities_module_def);
submodule = bpygpu_create_module(&pygpu_capabilities_module_def);
return submodule;
}

View File

@ -26,8 +26,6 @@
static PyObject *pygpu_IndexBuf__tp_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds)
{
BPYGPU_IS_INIT_OR_ERROR_OBJ;
const char *error_prefix = "IndexBuf.__new__";
bool ok = true;

View File

@ -267,7 +267,6 @@ static PyObject *pygpu_framebuffer__tp_new(PyTypeObject *UNUSED(self),
PyObject *args,
PyObject *kwds)
{
BPYGPU_IS_INIT_OR_ERROR_OBJ;
if (!GPU_context_active_get()) {
PyErr_SetString(PyExc_RuntimeError, "No active GPU context found");
return NULL;

View File

@ -24,6 +24,7 @@
#include "GPU_matrix.h"
#undef USE_GPU_PY_MATRIX_API
#include "gpu_py.h"
#include "gpu_py_matrix.h" /* own include */
/* -------------------------------------------------------------------- */
@ -542,9 +543,9 @@ PyObject *bpygpu_matrix_init(void)
{
PyObject *submodule;
submodule = PyModule_Create(&pygpu_matrix_module_def);
submodule = bpygpu_create_module(&pygpu_matrix_module_def);
if (PyType_Ready(&PyGPUMatrixStackContext_Type) < 0) {
if (bpygpu_finalize_type(&PyGPUMatrixStackContext_Type) < 0) {
return NULL;
}

View File

@ -211,8 +211,6 @@ static PyObject *pygpu_offscreen__tp_new(PyTypeObject *UNUSED(self),
PyObject *args,
PyObject *kwds)
{
BPYGPU_IS_INIT_OR_ERROR_OBJ;
GPUOffScreen *ofs = NULL;
int width, height;
struct PyC_StringEnum pygpu_textureformat = {pygpu_framebuffer_color_texture_formats, GPU_RGBA8};

View File

@ -14,6 +14,7 @@
#include "GPU_context.h"
#include "GPU_platform.h"
#include "gpu_py.h"
#include "gpu_py_platform.h" /* Own include. */
/* -------------------------------------------------------------------- */
@ -155,7 +156,7 @@ PyObject *bpygpu_platform_init(void)
{
PyObject *submodule;
submodule = PyModule_Create(&pygpu_platform_module_def);
submodule = bpygpu_create_module(&pygpu_platform_module_def);
return submodule;
}

View File

@ -20,6 +20,7 @@
#include "GPU_select.h"
#include "gpu_py.h"
#include "gpu_py_select.h" /* Own include. */
/* -------------------------------------------------------------------- */
@ -72,7 +73,7 @@ PyObject *bpygpu_select_init(void)
{
PyObject *submodule;
submodule = PyModule_Create(&pygpu_select_module_def);
submodule = bpygpu_create_module(&pygpu_select_module_def);
return submodule;
}

View File

@ -95,8 +95,6 @@ static int pygpu_shader_uniform_location_get(GPUShader *shader,
static PyObject *pygpu_shader__tp_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds)
{
BPYGPU_IS_INIT_OR_ERROR_OBJ;
struct {
const char *vertexcode;
const char *fragcode;
@ -835,8 +833,6 @@ PyDoc_STRVAR(
" :rtype: :class:`bpy.types.GPUShader`\n");
static PyObject *pygpu_shader_from_builtin(PyObject *UNUSED(self), PyObject *args, PyObject *kwds)
{
BPYGPU_IS_INIT_OR_ERROR_OBJ;
struct PyC_StringEnum pygpu_bultinshader = {pygpu_shader_builtin_items};
struct PyC_StringEnum pygpu_config = {pygpu_shader_config_items, GPU_SHADER_CFG_DEFAULT};
@ -954,7 +950,7 @@ PyObject *bpygpu_shader_init(void)
{
PyObject *submodule;
submodule = PyModule_Create(&pygpu_shader_module_def);
submodule = bpygpu_create_module(&pygpu_shader_module_def);
return submodule;
}

View File

@ -17,6 +17,7 @@
#include "../generic/py_capi_utils.h"
#include "../generic/python_utildefines.h"
#include "gpu_py.h"
#include "gpu_py_framebuffer.h"
#include "gpu_py_state.h" /* own include */
@ -445,7 +446,7 @@ PyObject *bpygpu_state_init(void)
{
PyObject *submodule;
submodule = PyModule_Create(&pygpu_state_module_def);
submodule = bpygpu_create_module(&pygpu_state_module_def);
return submodule;
}

View File

@ -111,8 +111,6 @@ static int pygpu_texture_valid_check(BPyGPUTexture *bpygpu_tex)
static PyObject *pygpu_texture__tp_new(PyTypeObject *UNUSED(self), PyObject *args, PyObject *kwds)
{
BPYGPU_IS_INIT_OR_ERROR_OBJ;
PyObject *py_size;
int size[3] = {1, 1, 1};
int layers = 0;
@ -605,7 +603,7 @@ int bpygpu_ParseTexture(PyObject *o, void *p)
PyObject *bpygpu_texture_init(void)
{
PyObject *submodule;
submodule = PyModule_Create(&pygpu_texture_module_def);
submodule = bpygpu_create_module(&pygpu_texture_module_def);
return submodule;
}

View File

@ -11,6 +11,7 @@
#include "../generic/py_capi_utils.h"
#include "gpu_py.h"
#include "gpu_py_types.h" /* own include */
/* -------------------------------------------------------------------- */
@ -33,42 +34,42 @@ PyObject *bpygpu_types_init(void)
{
PyObject *submodule;
submodule = PyModule_Create(&pygpu_types_module_def);
submodule = bpygpu_create_module(&pygpu_types_module_def);
if (PyType_Ready(&BPyGPU_BufferType) < 0) {
if (bpygpu_finalize_type(&BPyGPU_BufferType) < 0) {
return NULL;
}
if (PyType_Ready(&BPyGPUVertFormat_Type) < 0) {
if (bpygpu_finalize_type(&BPyGPUVertFormat_Type) < 0) {
return NULL;
}
if (PyType_Ready(&BPyGPUVertBuf_Type) < 0) {
if (bpygpu_finalize_type(&BPyGPUVertBuf_Type) < 0) {
return NULL;
}
if (PyType_Ready(&BPyGPUIndexBuf_Type) < 0) {
if (bpygpu_finalize_type(&BPyGPUIndexBuf_Type) < 0) {
return NULL;
}
if (PyType_Ready(&BPyGPUBatch_Type) < 0) {
if (bpygpu_finalize_type(&BPyGPUBatch_Type) < 0) {
return NULL;
}
if (PyType_Ready(&BPyGPUOffScreen_Type) < 0) {
if (bpygpu_finalize_type(&BPyGPUOffScreen_Type) < 0) {
return NULL;
}
if (PyType_Ready(&BPyGPUShader_Type) < 0) {
if (bpygpu_finalize_type(&BPyGPUShader_Type) < 0) {
return NULL;
}
if (PyType_Ready(&BPyGPUTexture_Type) < 0) {
if (bpygpu_finalize_type(&BPyGPUTexture_Type) < 0) {
return NULL;
}
if (PyType_Ready(&BPyGPUFrameBuffer_Type) < 0) {
if (bpygpu_finalize_type(&BPyGPUFrameBuffer_Type) < 0) {
return NULL;
}
if (PyType_Ready(&BPyGPUUniformBuf_Type) < 0) {
if (bpygpu_finalize_type(&BPyGPUUniformBuf_Type) < 0) {
return NULL;
}
if (PyType_Ready(&BPyGPUShaderCreateInfo_Type) < 0) {
if (bpygpu_finalize_type(&BPyGPUShaderCreateInfo_Type) < 0) {
return NULL;
}
if (PyType_Ready(&BPyGPUStageInterfaceInfo_Type) < 0) {
if (bpygpu_finalize_type(&BPyGPUStageInterfaceInfo_Type) < 0) {
return NULL;
}

View File

@ -59,8 +59,6 @@ static PyObject *pygpu_uniformbuffer__tp_new(PyTypeObject *UNUSED(self),
PyObject *args,
PyObject *kwds)
{
BPYGPU_IS_INIT_OR_ERROR_OBJ;
GPUUniformBuf *ubo = NULL;
PyObject *pybuffer_obj;
char err_out[256] = "unknown error. See console";

View File

@ -1332,10 +1332,7 @@ struct wmDragAssetCatalog *WM_drag_get_asset_catalog_data(const struct wmDrag *d
/**
* \note Does not store \a asset in any way, so it's fine to pass a temporary.
*/
void WM_drag_add_asset_list_item(wmDrag *drag,
const struct bContext *C,
const struct AssetLibraryReference *asset_library_ref,
const struct AssetHandle *asset);
void WM_drag_add_asset_list_item(wmDrag *drag, const struct AssetHandle *asset);
const ListBase *WM_drag_asset_list_get(const wmDrag *drag);
const char *WM_drag_get_item_name(struct wmDrag *drag);

View File

@ -206,12 +206,11 @@ wmDrag *WM_drag_data_create(bContext *C, int icon, int type, void *poin, double
/* The asset-list case is special: We get multiple assets from context and attach them to the
* drag item. */
case WM_DRAG_ASSET_LIST: {
const AssetLibraryReference *asset_library = CTX_wm_asset_library_ref(C);
ListBase asset_file_links = CTX_data_collection_get(C, "selected_asset_files");
LISTBASE_FOREACH (const CollectionPointerLink *, link, &asset_file_links) {
const FileDirEntry *asset_file = static_cast<const FileDirEntry *>(link->ptr.data);
const AssetHandle asset_handle = {asset_file};
WM_drag_add_asset_list_item(drag, C, asset_library, &asset_handle);
WM_drag_add_asset_list_item(drag, &asset_handle);
}
BLI_freelistN(&asset_file_links);
break;
@ -711,12 +710,7 @@ wmDragAssetCatalog *WM_drag_get_asset_catalog_data(const wmDrag *drag)
return static_cast<wmDragAssetCatalog *>(drag->poin);
}
void WM_drag_add_asset_list_item(
wmDrag *drag,
/* Context only needed for the hack in #ED_asset_handle_get_full_library_path(). */
const bContext *C,
const AssetLibraryReference *asset_library_ref,
const AssetHandle *asset)
void WM_drag_add_asset_list_item(wmDrag *drag, const AssetHandle *asset)
{
BLI_assert(drag->type == WM_DRAG_ASSET_LIST);
@ -731,7 +725,7 @@ void WM_drag_add_asset_list_item(
}
else {
char asset_blend_path[FILE_MAX_LIBEXTRA];
ED_asset_handle_get_full_library_path(C, asset_library_ref, asset, asset_blend_path);
ED_asset_handle_get_full_library_path(asset, asset_blend_path);
drag_asset->is_external = true;
drag_asset->asset_data.external_info = WM_drag_create_asset_data(
asset, BLI_strdup(asset_blend_path), FILE_ASSET_IMPORT_APPEND);

View File

@ -922,6 +922,7 @@ static void wm_draw_window_offscreen(bContext *C, wmWindow *win, bool stereo)
}
}
else {
wm_draw_region_stereo_set(bmain, area, region, STEREO_LEFT_ID);
wm_draw_region_buffer_create(region, false, use_viewport);
wm_draw_region_bind(region, 0);
ED_region_do_draw(C, region);

View File

@ -247,7 +247,7 @@ class TestBlendLibLinkIndirect(TestBlendLibLinkHelper):
assert material.users == 2
# Currently linked data which has no more local user never gets reset to indirectly linked status.
# ~ assert material.is_library_indirect == True
assert material.is_library_indirect == True
bpy.ops.wm.open_mainfile(filepath=output_work_path, load_ui=False)
@ -264,7 +264,7 @@ class TestBlendLibLinkIndirect(TestBlendLibLinkHelper):
assert material.users == 2 # Fake user is not cleared when linking.
# Currently even re-reading the .blend file will not properly reset tag for indirectly linked data,
# if their reference was written in the .blend file.
# ~ assert material.is_library_indirect == True
assert material.is_library_indirect == True
assert mesh.library is not None
assert mesh.use_fake_user is False

View File

@ -146,6 +146,8 @@ def check_lib_linking():
with bpy.data.libraries.load(lib_path, link=True) as (data_from, data_to):
data_to.scenes = ["Scene_lib"]
bpy.context.window.scene = bpy.data.scenes["Scene_lib"]
o = bpy.data.scenes["Scene_lib"].objects['Unique_Cube']
expect_false_or_abort(o.prop_array[0].test_prop == bpy.data.scenes["Scene_lib"].objects['Light'])
@ -158,9 +160,10 @@ def check_lib_linking():
def check_linked_scene_copying():
# full copy of the scene with datablock props
bpy.ops.wm.open_mainfile(filepath=test_path)
bpy.context.window.scene = bpy.data.scenes["Scene_lib"]
bpy.ops.scene.new(type='FULL_COPY')
bpy.context.window.scene = get_scene("lib.blend", "Scene_lib")
# check save/open
bpy.ops.wm.save_as_mainfile(filepath=test_path)
bpy.ops.wm.open_mainfile(filepath=test_path)