UI: Region polling support #105088

Merged
Julian Eisel merged 39 commits from JulianEisel/blender:temp-region-poll into main 2023-04-05 15:30:46 +02:00
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)