Nodes: support storing internal data in Bundle
Currently, bundles can only store socket values of Geometry Nodes. However, it can make sense to store other kinds of data too. Specifically, this patch adds support for storing arbitrary internal data in a bundle. This is useful when storing e.g. the physics world when implementing a proper physics solver for Geometry Nodes (like in #143171). One can still see that the data exists in Geometry Nodes in the tooltip, but one can't extract it. Built-in nodes can still read that data. Storing built-in data in bundles can also be done as an alternative to having a new "internal data socket" as we talked in a workshop in the past: https://code.blender.org/2024/11/geometry-nodes-workshop-october-2024/#internal-data-sockets A bundle still has to be copyable. Internal data is expected to use implicit sharing. That way copying it just requires increasing the user count of the data. Pull Request: https://projects.blender.org/blender/blender/pulls/143472
This commit is contained in:
@@ -150,12 +150,20 @@ class StringBakeItem : public BakeItem {
|
||||
*/
|
||||
class BundleBakeItem : public BakeItem {
|
||||
public:
|
||||
struct Item {
|
||||
std::string key;
|
||||
struct SocketValue {
|
||||
std::string socket_idname;
|
||||
std::unique_ptr<BakeItem> value;
|
||||
};
|
||||
|
||||
struct InternalValue {
|
||||
ImplicitSharingPtr<> value;
|
||||
};
|
||||
|
||||
struct Item {
|
||||
std::string key;
|
||||
std::variant<SocketValue, InternalValue> value;
|
||||
};
|
||||
|
||||
Vector<Item> items;
|
||||
};
|
||||
|
||||
|
||||
@@ -1497,11 +1497,14 @@ static void serialize_bake_item(const BakeItem &item,
|
||||
r_io_item.append_str("type", "BUNDLE");
|
||||
ArrayValue &io_items = *r_io_item.append_array("items");
|
||||
for (const BundleBakeItem::Item &item : bundle_state_item->items) {
|
||||
DictionaryValue &io_bundle_item = *io_items.append_dict();
|
||||
io_bundle_item.append_str("key", item.key);
|
||||
io_bundle_item.append_str("socket_idname", item.socket_idname);
|
||||
io::serialize::DictionaryValue &io_bundle_item_value = *io_bundle_item.append_dict("value");
|
||||
serialize_bake_item(*item.value, blob_writer, blob_sharing, io_bundle_item_value);
|
||||
if (const auto *socket_value = std::get_if<BundleBakeItem::SocketValue>(&item.value)) {
|
||||
DictionaryValue &io_bundle_item = *io_items.append_dict();
|
||||
io_bundle_item.append_str("key", item.key);
|
||||
io_bundle_item.append_str("socket_idname", socket_value->socket_idname);
|
||||
io::serialize::DictionaryValue &io_bundle_item_value = *io_bundle_item.append_dict(
|
||||
"value");
|
||||
serialize_bake_item(*socket_value->value, blob_writer, blob_sharing, io_bundle_item_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1614,7 +1617,8 @@ static std::unique_ptr<BakeItem> deserialize_bake_item(const DictionaryValue &io
|
||||
if (!value) {
|
||||
return {};
|
||||
}
|
||||
bundle->items.append(BundleBakeItem::Item{*key, *socket_idname, std::move(value)});
|
||||
bundle->items.append(BundleBakeItem::Item{
|
||||
*key, BundleBakeItem::SocketValue{*socket_idname, std::move(value)}});
|
||||
}
|
||||
return bundle;
|
||||
}
|
||||
|
||||
@@ -92,11 +92,27 @@ static std::unique_ptr<BakeItem> move_common_socket_value_to_bake_item(
|
||||
if (bundle_ptr) {
|
||||
const nodes::Bundle &bundle = *bundle_ptr;
|
||||
for (const nodes::Bundle::StoredItem &bundle_item : bundle.items()) {
|
||||
if (std::unique_ptr<BakeItem> bake_item = move_common_socket_value_to_bake_item(
|
||||
*bundle_item.type, bundle_item.value, std::nullopt, r_geometry_bake_items))
|
||||
if (const auto *socket_value = std::get_if<nodes::BundleItemSocketValue>(
|
||||
&bundle_item.value.value))
|
||||
{
|
||||
if (std::unique_ptr<BakeItem> bake_item = move_common_socket_value_to_bake_item(
|
||||
*socket_value->type, socket_value->value, std::nullopt, r_geometry_bake_items))
|
||||
{
|
||||
bundle_bake_item->items.append(BundleBakeItem::Item{
|
||||
bundle_item.key,
|
||||
BundleBakeItem::SocketValue{socket_value->type->idname, std::move(bake_item)}});
|
||||
}
|
||||
}
|
||||
else if (const auto *internal_value = std::get_if<nodes::BundleItemInternalValue>(
|
||||
&bundle_item.value.value))
|
||||
{
|
||||
const ImplicitSharingInfo *sharing_info = internal_value->value.get();
|
||||
if (sharing_info) {
|
||||
sharing_info->add_user();
|
||||
}
|
||||
bundle_bake_item->items.append(BundleBakeItem::Item{
|
||||
bundle_item.key, bundle_item.type->idname, std::move(bake_item)});
|
||||
bundle_item.key,
|
||||
BundleBakeItem::InternalValue{ImplicitSharingPtr<>{sharing_info}}});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -271,21 +287,34 @@ Array<std::unique_ptr<BakeItem>> move_socket_values_to_bake_items(const Span<voi
|
||||
nodes::BundlePtr bundle_ptr = nodes::Bundle::create();
|
||||
nodes::Bundle &bundle = const_cast<nodes::Bundle &>(*bundle_ptr);
|
||||
for (const BundleBakeItem::Item &item : item->items) {
|
||||
const bNodeSocketType *stype = node_socket_type_find(item.socket_idname);
|
||||
if (!stype) {
|
||||
return false;
|
||||
if (const auto *socket_value = std::get_if<BundleBakeItem::SocketValue>(&item.value)) {
|
||||
const bNodeSocketType *stype = node_socket_type_find(socket_value->socket_idname);
|
||||
if (!stype) {
|
||||
return false;
|
||||
}
|
||||
if (!stype->geometry_nodes_cpp_type) {
|
||||
return false;
|
||||
}
|
||||
BUFFER_FOR_CPP_TYPE_VALUE(*stype->geometry_nodes_cpp_type, buffer);
|
||||
if (!copy_bake_item_to_socket_value(
|
||||
*socket_value->value, stype->type, {}, r_attribute_map, buffer))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bundle.add(item.key, nodes::BundleItemSocketValue{stype, buffer});
|
||||
stype->geometry_nodes_cpp_type->destruct(buffer);
|
||||
}
|
||||
if (!stype->geometry_nodes_cpp_type) {
|
||||
return false;
|
||||
}
|
||||
BUFFER_FOR_CPP_TYPE_VALUE(*stype->geometry_nodes_cpp_type, buffer);
|
||||
if (!copy_bake_item_to_socket_value(
|
||||
*item.value, stype->type, {}, r_attribute_map, buffer))
|
||||
if (const auto *internal_value = std::get_if<BundleBakeItem::InternalValue>(&item.value))
|
||||
{
|
||||
return false;
|
||||
const auto *internal_data = dynamic_cast<const nodes::BundleItemInternalValueMixin *>(
|
||||
internal_value->value.get());
|
||||
if (!internal_data) {
|
||||
continue;
|
||||
}
|
||||
internal_data->add_user();
|
||||
bundle.add(item.key,
|
||||
nodes::BundleItemInternalValue{ImplicitSharingPtr{internal_data}});
|
||||
}
|
||||
bundle.add(item.key, *stype, buffer);
|
||||
stype->geometry_nodes_cpp_type->destruct(buffer);
|
||||
}
|
||||
bke::SocketValueVariant::ConstructIn(r_value, std::move(bundle_ptr));
|
||||
return true;
|
||||
|
||||
@@ -26,6 +26,8 @@ template<typename T = ImplicitSharingInfo, bool IsStrong = true> class ImplicitS
|
||||
const T *data_ = nullptr;
|
||||
|
||||
public:
|
||||
using element_type = T;
|
||||
|
||||
ImplicitSharingPtr() = default;
|
||||
|
||||
explicit ImplicitSharingPtr(const T *data) : data_(data) {}
|
||||
@@ -219,4 +221,8 @@ class ImplicitSharingPtrAndData {
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T> static constexpr bool is_ImplicitSharingPtr_strong_v = false;
|
||||
template<typename T>
|
||||
static constexpr bool is_ImplicitSharingPtr_strong_v<ImplicitSharingPtr<T, true>> = true;
|
||||
|
||||
} // namespace blender
|
||||
|
||||
@@ -701,7 +701,16 @@ class SocketTooltipBuilder {
|
||||
});
|
||||
for (const geo_log::BundleValueLog::Item &item : sorted_items) {
|
||||
this->add_space();
|
||||
const std::string type_name = TIP_(item.type->label);
|
||||
std::string type_name;
|
||||
if (const bke::bNodeSocketType *const *socket_type =
|
||||
std::get_if<const bke::bNodeSocketType *>(&item.type))
|
||||
{
|
||||
type_name = TIP_((*socket_type)->label);
|
||||
}
|
||||
else if (const StringRefNull *internal_type_name = std::get_if<StringRefNull>(&item.type))
|
||||
{
|
||||
type_name = *internal_type_name;
|
||||
}
|
||||
this->add_text_field_mono(
|
||||
fmt::format(fmt::runtime("\u2022 \"{}\" ({})\n"), item.key, type_name));
|
||||
}
|
||||
|
||||
@@ -14,6 +14,37 @@
|
||||
|
||||
namespace blender::nodes {
|
||||
|
||||
struct BundleItemSocketValue {
|
||||
/** The type of data referenced. It uses #bNodeSocketType::geometry_nodes_cpp_type. */
|
||||
const bke::bNodeSocketType *type;
|
||||
/** Non-owning pointer to the value. The memory is owned by the Bundle directly. */
|
||||
void *value;
|
||||
};
|
||||
|
||||
/**
|
||||
* Other classes can derive from this to be able to store custom internal data in a bundle.
|
||||
*/
|
||||
class BundleItemInternalValueMixin : public ImplicitSharingMixin {
|
||||
public:
|
||||
/** UI name for the type. */
|
||||
virtual StringRefNull type_name() const = 0;
|
||||
};
|
||||
|
||||
struct BundleItemInternalValue {
|
||||
ImplicitSharingPtr<BundleItemInternalValueMixin> value;
|
||||
};
|
||||
|
||||
struct BundleItemValue {
|
||||
std::variant<BundleItemSocketValue, BundleItemInternalValue> value;
|
||||
|
||||
/**
|
||||
* Attempts to cast the stored value to the given type. This may do implicit conversions.
|
||||
*/
|
||||
template<typename T>
|
||||
std::optional<T> as_socket_value(const bke::bNodeSocketType &socket_type) const;
|
||||
template<typename T> std::optional<T> as() const;
|
||||
};
|
||||
|
||||
/**
|
||||
* A bundle is a map containing keys and their corresponding values. Values are stored as the type
|
||||
* they have in Geometry Nodes (#bNodeSocketType::geometry_nodes_cpp_type).
|
||||
@@ -24,8 +55,7 @@ class Bundle : public ImplicitSharingMixin {
|
||||
public:
|
||||
struct StoredItem {
|
||||
std::string key;
|
||||
const bke::bNodeSocketType *type;
|
||||
void *value;
|
||||
BundleItemValue value;
|
||||
};
|
||||
|
||||
private:
|
||||
@@ -33,17 +63,6 @@ class Bundle : public ImplicitSharingMixin {
|
||||
Vector<void *> buffers_;
|
||||
|
||||
public:
|
||||
struct Item {
|
||||
const bke::bNodeSocketType *type;
|
||||
const void *value;
|
||||
|
||||
/**
|
||||
* Attempts to cast the stored value to the given type. This may do implicit conversions.
|
||||
*/
|
||||
template<typename T> std::optional<T> as(const bke::bNodeSocketType &socket_type) const;
|
||||
template<typename T> std::optional<T> as() const;
|
||||
};
|
||||
|
||||
Bundle();
|
||||
Bundle(const Bundle &other);
|
||||
Bundle(Bundle &&other) noexcept;
|
||||
@@ -53,12 +72,12 @@ class Bundle : public ImplicitSharingMixin {
|
||||
|
||||
static BundlePtr create();
|
||||
|
||||
bool add(StringRef key, const bke::bNodeSocketType &type, const void *value);
|
||||
void add_new(StringRef key, const bke::bNodeSocketType &type, const void *value);
|
||||
void add_override(StringRef key, const bke::bNodeSocketType &type, const void *value);
|
||||
bool add_path(StringRef path, const bke::bNodeSocketType &type, const void *value);
|
||||
void add_path_new(StringRef path, const bke::bNodeSocketType &type, const void *value);
|
||||
void add_path_override(StringRef path, const bke::bNodeSocketType &type, const void *value);
|
||||
bool add(StringRef key, const BundleItemValue &value);
|
||||
void add_new(StringRef key, const BundleItemValue &value);
|
||||
void add_override(StringRef key, const BundleItemValue &value);
|
||||
bool add_path(StringRef path, const BundleItemValue &value);
|
||||
void add_path_new(StringRef path, const BundleItemValue &value);
|
||||
void add_path_override(StringRef path, const BundleItemValue &value);
|
||||
|
||||
template<typename T> void add(StringRef key, T value);
|
||||
template<typename T> void add_override(StringRef key, T value);
|
||||
@@ -69,9 +88,9 @@ class Bundle : public ImplicitSharingMixin {
|
||||
bool contains(StringRef key) const;
|
||||
bool contains_path(StringRef path) const;
|
||||
|
||||
std::optional<Item> lookup(StringRef key) const;
|
||||
std::optional<Item> lookup_path(Span<StringRef> path) const;
|
||||
std::optional<Item> lookup_path(StringRef path) const;
|
||||
const BundleItemValue *lookup(StringRef key) const;
|
||||
const BundleItemValue *lookup_path(Span<StringRef> path) const;
|
||||
const BundleItemValue *lookup_path(StringRef path) const;
|
||||
template<typename T> std::optional<T> lookup(StringRef key) const;
|
||||
template<typename T> std::optional<T> lookup_path(StringRef path) const;
|
||||
|
||||
@@ -83,18 +102,28 @@ class Bundle : public ImplicitSharingMixin {
|
||||
BundlePtr copy() const;
|
||||
|
||||
void delete_self() override;
|
||||
|
||||
/** Create the combined path by inserting '/' between each element. */
|
||||
static std::string combine_path(const Span<StringRef> path);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
inline std::optional<T> Bundle::Item::as(const bke::bNodeSocketType &socket_type) const
|
||||
inline std::optional<T> BundleItemValue::as_socket_value(
|
||||
const bke::bNodeSocketType &dst_socket_type) const
|
||||
{
|
||||
if (!this->value || !this->type) {
|
||||
const BundleItemSocketValue *socket_value = std::get_if<BundleItemSocketValue>(&this->value);
|
||||
if (!socket_value) {
|
||||
return std::nullopt;
|
||||
}
|
||||
const void *converted_value = this->value;
|
||||
BUFFER_FOR_CPP_TYPE_VALUE(*socket_type.geometry_nodes_cpp_type, buffer);
|
||||
if (this->type != &socket_type) {
|
||||
if (!implicitly_convert_socket_value(*this->type, this->value, socket_type, buffer)) {
|
||||
if (!socket_value->value || !socket_value->type) {
|
||||
return std::nullopt;
|
||||
}
|
||||
const void *converted_value = socket_value->value;
|
||||
BUFFER_FOR_CPP_TYPE_VALUE(*dst_socket_type.geometry_nodes_cpp_type, buffer);
|
||||
if (socket_value->type != &dst_socket_type) {
|
||||
if (!implicitly_convert_socket_value(
|
||||
*socket_value->type, socket_value->value, dst_socket_type, buffer))
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
converted_value = buffer;
|
||||
@@ -114,7 +143,7 @@ template<typename T> constexpr bool is_valid_static_bundle_item_type()
|
||||
if constexpr (fn::is_field_v<T>) {
|
||||
return geo_nodes_is_field_base_type_v<typename T::base_type>;
|
||||
}
|
||||
if constexpr (is_same_any_v<T, BundlePtr, ClosurePtr>) {
|
||||
if constexpr (is_same_any_v<T, BundlePtr, ClosurePtr, ListPtr>) {
|
||||
return true;
|
||||
}
|
||||
return !geo_nodes_type_stored_as_SocketValueVariant_v<T>;
|
||||
@@ -141,11 +170,52 @@ template<typename T> inline const bke::bNodeSocketType *socket_type_info_by_stat
|
||||
return bke::node_socket_type_find_static(*socket_type);
|
||||
}
|
||||
|
||||
template<typename T> inline std::optional<T> Bundle::Item::as() const
|
||||
template<typename T> constexpr bool is_valid_internal_bundle_item_type()
|
||||
{
|
||||
static_assert(is_valid_static_bundle_item_type<T>());
|
||||
if (const bke::bNodeSocketType *socket_type = socket_type_info_by_static_type<T>()) {
|
||||
return this->as<T>(*socket_type);
|
||||
if constexpr (is_ImplicitSharingPtr_strong_v<T>) {
|
||||
if constexpr (std::is_base_of_v<BundleItemInternalValueMixin, typename T::element_type>) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename T> inline std::optional<T> BundleItemValue::as() const
|
||||
{
|
||||
static_assert(is_valid_static_bundle_item_type<T>() || is_valid_internal_bundle_item_type<T>());
|
||||
if constexpr (is_valid_internal_bundle_item_type<T>()) {
|
||||
using SharingInfoT = typename T::element_type;
|
||||
const auto *internal_value = std::get_if<BundleItemInternalValue>(&this->value);
|
||||
if (!internal_value) {
|
||||
return std::nullopt;
|
||||
}
|
||||
const BundleItemInternalValueMixin *sharing_info = internal_value->value.get();
|
||||
const SharingInfoT *converted_value = dynamic_cast<const SharingInfoT *>(sharing_info);
|
||||
if (!converted_value) {
|
||||
return std::nullopt;
|
||||
}
|
||||
sharing_info->add_user();
|
||||
return ImplicitSharingPtr<SharingInfoT>{converted_value};
|
||||
}
|
||||
if constexpr (std::is_same_v<T, ListPtr>) {
|
||||
const BundleItemSocketValue *socket_value = std::get_if<BundleItemSocketValue>(&this->value);
|
||||
if (!socket_value) {
|
||||
return std::nullopt;
|
||||
}
|
||||
if (!socket_value->value || !socket_value->type) {
|
||||
return std::nullopt;
|
||||
}
|
||||
if (!socket_value->type->geometry_nodes_cpp_type->is<bke::SocketValueVariant>()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
const auto *value = static_cast<const bke::SocketValueVariant *>(socket_value->value);
|
||||
if (value->is_list()) {
|
||||
return value->get<ListPtr>();
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
if (const bke::bNodeSocketType *dst_socket_type = socket_type_info_by_static_type<T>()) {
|
||||
return this->as_socket_value<T>(*dst_socket_type);
|
||||
}
|
||||
/* Can't lookup this type directly currently. */
|
||||
BLI_assert_unreachable();
|
||||
@@ -154,7 +224,7 @@ template<typename T> inline std::optional<T> Bundle::Item::as() const
|
||||
|
||||
template<typename T> inline std::optional<T> Bundle::lookup(const StringRef key) const
|
||||
{
|
||||
const std::optional<Item> item = this->lookup(key);
|
||||
const BundleItemValue *item = this->lookup(key);
|
||||
if (!item) {
|
||||
return std::nullopt;
|
||||
}
|
||||
@@ -163,7 +233,7 @@ template<typename T> inline std::optional<T> Bundle::lookup(const StringRef key)
|
||||
|
||||
template<typename T> inline std::optional<T> Bundle::lookup_path(const StringRef path) const
|
||||
{
|
||||
const std::optional<Item> item = this->lookup_path(path);
|
||||
const BundleItemValue *item = this->lookup_path(path);
|
||||
if (!item) {
|
||||
return std::nullopt;
|
||||
}
|
||||
@@ -173,43 +243,61 @@ template<typename T> inline std::optional<T> Bundle::lookup_path(const StringRef
|
||||
template<typename T, typename Fn> inline void to_stored_type(T &&value, Fn &&fn)
|
||||
{
|
||||
using DecayT = std::decay_t<T>;
|
||||
static_assert(is_valid_static_bundle_item_type<DecayT>());
|
||||
const bke::bNodeSocketType *socket_type = socket_type_info_by_static_type<DecayT>();
|
||||
BLI_assert(socket_type);
|
||||
if constexpr (geo_nodes_type_stored_as_SocketValueVariant_v<DecayT>) {
|
||||
auto value_variant = bke::SocketValueVariant::From(std::forward<T>(value));
|
||||
fn(*socket_type, &value_variant);
|
||||
static_assert(
|
||||
is_valid_static_bundle_item_type<DecayT>() || is_valid_internal_bundle_item_type<DecayT>() ||
|
||||
is_same_any_v<DecayT, BundleItemValue, BundleItemSocketValue, BundleItemInternalValue>);
|
||||
if constexpr (std::is_same_v<DecayT, BundleItemValue>) {
|
||||
fn(std::forward<T>(value));
|
||||
}
|
||||
else if constexpr (std::is_same_v<DecayT, BundleItemSocketValue>) {
|
||||
fn(BundleItemValue{std::forward<T>(value)});
|
||||
}
|
||||
else if constexpr (std::is_same_v<DecayT, BundleItemInternalValue>) {
|
||||
fn(BundleItemValue{std::forward<T>(value)});
|
||||
}
|
||||
else if constexpr (is_valid_internal_bundle_item_type<DecayT>()) {
|
||||
const BundleItemInternalValueMixin *sharing_info = value.get();
|
||||
if (sharing_info) {
|
||||
sharing_info->add_user();
|
||||
}
|
||||
fn(BundleItemValue{BundleItemInternalValue{ImplicitSharingPtr{sharing_info}}});
|
||||
}
|
||||
else if (const bke::bNodeSocketType *socket_type = socket_type_info_by_static_type<DecayT>()) {
|
||||
if constexpr (geo_nodes_type_stored_as_SocketValueVariant_v<DecayT>) {
|
||||
auto value_variant = bke::SocketValueVariant::From(std::forward<T>(value));
|
||||
fn(BundleItemValue{BundleItemSocketValue{socket_type, &value_variant}});
|
||||
}
|
||||
else {
|
||||
fn(BundleItemValue{BundleItemSocketValue{socket_type, &value}});
|
||||
}
|
||||
}
|
||||
else {
|
||||
fn(*socket_type, &value);
|
||||
/* All allowed types should be handled above already. */
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T> inline void Bundle::add(const StringRef key, T value)
|
||||
{
|
||||
to_stored_type(value, [&](const bke::bNodeSocketType &type, const void *value) {
|
||||
this->add(key, type, value);
|
||||
});
|
||||
to_stored_type(value, [&](const BundleItemValue &item_value) { this->add(key, item_value); });
|
||||
}
|
||||
|
||||
template<typename T> inline void Bundle::add_path(const StringRef path, T value)
|
||||
{
|
||||
to_stored_type(value, [&](const bke::bNodeSocketType &type, const void *value) {
|
||||
this->add_path(path, type, value);
|
||||
});
|
||||
to_stored_type(value,
|
||||
[&](const BundleItemValue &item_value) { this->add_path(path, item_value); });
|
||||
}
|
||||
|
||||
template<typename T> inline void Bundle::add_override(const StringRef key, T value)
|
||||
{
|
||||
to_stored_type(value, [&](const bke::bNodeSocketType &type, const void *value) {
|
||||
this->add_override(key, type, value);
|
||||
});
|
||||
to_stored_type(value,
|
||||
[&](const BundleItemValue &item_value) { this->add_override(key, item_value); });
|
||||
}
|
||||
|
||||
template<typename T> inline void Bundle::add_path_override(const StringRef path, T value)
|
||||
{
|
||||
to_stored_type(value, [&](const bke::bNodeSocketType &type, const void *value) {
|
||||
this->add_path_override(path, type, value);
|
||||
to_stored_type(value, [&](const BundleItemValue &item_value) {
|
||||
this->add_path_override(path, item_value);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -191,7 +191,7 @@ class BundleValueLog : public ValueLog {
|
||||
public:
|
||||
struct Item {
|
||||
std::string key;
|
||||
const bke::bNodeSocketType *type;
|
||||
std::variant<const bke::bNodeSocketType *, StringRefNull> type;
|
||||
};
|
||||
|
||||
Vector<Item> items;
|
||||
|
||||
@@ -116,7 +116,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
}
|
||||
void *input_ptr = params.low_level_lazy_function_params().try_get_input_data_ptr(i);
|
||||
BLI_assert(input_ptr);
|
||||
bundle.add(name, *stype, input_ptr);
|
||||
bundle.add(name, BundleItemSocketValue{stype, input_ptr});
|
||||
}
|
||||
|
||||
params.set_output("Bundle", std::move(bundle_ptr));
|
||||
|
||||
@@ -123,14 +123,23 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
if (!stype || !stype->geometry_nodes_cpp_type) {
|
||||
continue;
|
||||
}
|
||||
const std::optional<Bundle::Item> value = bundle->lookup(name);
|
||||
const BundleItemValue *value = bundle->lookup(name);
|
||||
if (!value) {
|
||||
params.error_message_add(NodeWarningType::Error,
|
||||
fmt::format(fmt::runtime(TIP_("Value not found: \"{}\"")), name));
|
||||
continue;
|
||||
}
|
||||
const auto *socket_value = std::get_if<BundleItemSocketValue>(&value->value);
|
||||
if (!socket_value) {
|
||||
params.error_message_add(
|
||||
NodeWarningType::Error,
|
||||
fmt::format("{}: \"{}\"", TIP_("Cannot get internal value from bundle"), name));
|
||||
continue;
|
||||
}
|
||||
void *output_ptr = lf_params.get_output_data_ptr(i);
|
||||
if (!implicitly_convert_socket_value(*value->type, value->value, *stype, output_ptr)) {
|
||||
if (!implicitly_convert_socket_value(
|
||||
*socket_value->type, socket_value->value, *stype, output_ptr))
|
||||
{
|
||||
construct_socket_default_value(*stype, output_ptr);
|
||||
}
|
||||
lf_params.output_set(i);
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "BKE_node_socket_value.hh"
|
||||
#include "BLI_cpp_type.hh"
|
||||
|
||||
@@ -46,7 +48,11 @@ Bundle::Bundle() = default;
|
||||
Bundle::~Bundle()
|
||||
{
|
||||
for (StoredItem &item : items_) {
|
||||
item.type->geometry_nodes_cpp_type->destruct(item.value);
|
||||
if (BundleItemSocketValue *socket_value = std::get_if<BundleItemSocketValue>(
|
||||
&item.value.value))
|
||||
{
|
||||
socket_value->type->geometry_nodes_cpp_type->destruct(socket_value->value);
|
||||
}
|
||||
}
|
||||
for (void *buffer : buffers_) {
|
||||
MEM_freeN(buffer);
|
||||
@@ -56,7 +62,7 @@ Bundle::~Bundle()
|
||||
Bundle::Bundle(const Bundle &other)
|
||||
{
|
||||
for (const StoredItem &item : other.items_) {
|
||||
this->add_new(item.key, *item.type, item.value);
|
||||
this->add_new(item.key, item.value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,35 +96,48 @@ Bundle &Bundle::operator=(Bundle &&other) noexcept
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Bundle::add_new(const StringRef key, const bke::bNodeSocketType &type, const void *value)
|
||||
[[maybe_unused]] static bool is_valid_key(const StringRef key)
|
||||
{
|
||||
BLI_assert(!this->contains(key));
|
||||
BLI_assert(type.geometry_nodes_cpp_type);
|
||||
const CPPType &cpp_type = *type.geometry_nodes_cpp_type;
|
||||
void *buffer = MEM_mallocN_aligned(cpp_type.size, cpp_type.alignment, __func__);
|
||||
cpp_type.copy_construct(value, buffer);
|
||||
items_.append(StoredItem{std::move(key), &type, buffer});
|
||||
buffers_.append(buffer);
|
||||
return key.find('/') == StringRef::not_found;
|
||||
}
|
||||
|
||||
void Bundle::add_override(const StringRef key, const bke::bNodeSocketType &type, const void *value)
|
||||
void Bundle::add_new(const StringRef key, const BundleItemValue &value)
|
||||
{
|
||||
BLI_assert(is_valid_key(key));
|
||||
if (const BundleItemSocketValue *socket_value = std::get_if<BundleItemSocketValue>(&value.value))
|
||||
{
|
||||
const bke::bNodeSocketType &type = *socket_value->type;
|
||||
BLI_assert(type.geometry_nodes_cpp_type);
|
||||
const CPPType &cpp_type = *type.geometry_nodes_cpp_type;
|
||||
void *buffer = MEM_mallocN_aligned(cpp_type.size, cpp_type.alignment, __func__);
|
||||
cpp_type.copy_construct(socket_value->value, buffer);
|
||||
items_.append(StoredItem{std::move(key), {BundleItemSocketValue{&type, buffer}}});
|
||||
buffers_.append(buffer);
|
||||
}
|
||||
else if (std::holds_alternative<BundleItemInternalValue>(value.value)) {
|
||||
items_.append(StoredItem{std::move(key), value});
|
||||
}
|
||||
else {
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
void Bundle::add_override(const StringRef key, const BundleItemValue &value)
|
||||
{
|
||||
this->remove(key);
|
||||
this->add_new(key, type, value);
|
||||
this->add_new(key, value);
|
||||
}
|
||||
|
||||
bool Bundle::add(const StringRef key, const bke::bNodeSocketType &type, const void *value)
|
||||
bool Bundle::add(const StringRef key, const BundleItemValue &value)
|
||||
{
|
||||
if (this->contains(key)) {
|
||||
return false;
|
||||
}
|
||||
this->add_new(key, type, value);
|
||||
this->add_new(key, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Bundle::add_path_override(const StringRef path,
|
||||
const bke::bNodeSocketType &type,
|
||||
const void *value)
|
||||
void Bundle::add_path_override(const StringRef path, const BundleItemValue &value)
|
||||
{
|
||||
BLI_assert(!path.is_empty());
|
||||
BLI_assert(!path.endswith("/"));
|
||||
@@ -127,15 +146,11 @@ void Bundle::add_path_override(const StringRef path,
|
||||
if (sep == StringRef::not_found) {
|
||||
const StringRef key = path;
|
||||
this->remove(key);
|
||||
this->add_new(key, type, value);
|
||||
this->add_new(key, value);
|
||||
return;
|
||||
}
|
||||
const StringRef first_part = path.substr(0, sep);
|
||||
BundlePtr child_bundle;
|
||||
const std::optional<Bundle::Item> item = this->lookup(first_part);
|
||||
if (item && item->type->type == SOCK_BUNDLE) {
|
||||
child_bundle = static_cast<const bke::SocketValueVariant *>(item->value)->get<BundlePtr>();
|
||||
}
|
||||
BundlePtr child_bundle = this->lookup<BundlePtr>(first_part).value_or(nullptr);
|
||||
if (!child_bundle) {
|
||||
child_bundle = Bundle::create();
|
||||
}
|
||||
@@ -144,55 +159,53 @@ void Bundle::add_path_override(const StringRef path,
|
||||
child_bundle = child_bundle->copy();
|
||||
}
|
||||
child_bundle->tag_ensured_mutable();
|
||||
const_cast<Bundle &>(*child_bundle).add_path_override(path.substr(sep + 1), type, value);
|
||||
const_cast<Bundle &>(*child_bundle).add_path_override(path.substr(sep + 1), value);
|
||||
bke::SocketValueVariant child_bundle_value = bke::SocketValueVariant::From(
|
||||
std::move(child_bundle));
|
||||
this->add(first_part, *bke::node_socket_type_find_static(SOCK_BUNDLE), &child_bundle_value);
|
||||
this->add(
|
||||
first_part,
|
||||
BundleItemSocketValue{bke::node_socket_type_find_static(SOCK_BUNDLE), &child_bundle_value});
|
||||
}
|
||||
|
||||
bool Bundle::add_path(StringRef path, const bke::bNodeSocketType &type, const void *value)
|
||||
bool Bundle::add_path(StringRef path, const BundleItemValue &value)
|
||||
{
|
||||
if (this->contains_path(path)) {
|
||||
return false;
|
||||
}
|
||||
this->add_path_new(path, type, value);
|
||||
this->add_path_new(path, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Bundle::add_path_new(StringRef path, const bke::bNodeSocketType &type, const void *value)
|
||||
void Bundle::add_path_new(StringRef path, const BundleItemValue &value)
|
||||
{
|
||||
BLI_assert(!this->contains_path(path));
|
||||
this->add_path_override(path, type, value);
|
||||
this->add_path_override(path, value);
|
||||
}
|
||||
|
||||
std::optional<Bundle::Item> Bundle::lookup(const StringRef key) const
|
||||
const BundleItemValue *Bundle::lookup(const StringRef key) const
|
||||
{
|
||||
for (const StoredItem &item : items_) {
|
||||
if (item.key == key) {
|
||||
return Item{item.type, item.value};
|
||||
return &item.value;
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::optional<Bundle::Item> Bundle::lookup_path(const Span<StringRef> path) const
|
||||
const BundleItemValue *Bundle::lookup_path(const Span<StringRef> path) const
|
||||
{
|
||||
BLI_assert(!path.is_empty());
|
||||
const StringRef first_elem = path[0];
|
||||
const std::optional<Bundle::Item> item = this->lookup(first_elem);
|
||||
const BundleItemValue *item = this->lookup(first_elem);
|
||||
if (!item) {
|
||||
return std::nullopt;
|
||||
return nullptr;
|
||||
}
|
||||
if (path.size() == 1) {
|
||||
return item;
|
||||
}
|
||||
if (item->type->type != SOCK_BUNDLE) {
|
||||
return std::nullopt;
|
||||
}
|
||||
const BundlePtr child_bundle =
|
||||
static_cast<const bke::SocketValueVariant *>(item->value)->get<BundlePtr>();
|
||||
const BundlePtr child_bundle = item->as<BundlePtr>().value_or(nullptr);
|
||||
if (!child_bundle) {
|
||||
return std::nullopt;
|
||||
return nullptr;
|
||||
}
|
||||
return child_bundle->lookup_path(path.drop_front(1));
|
||||
}
|
||||
@@ -213,7 +226,7 @@ static Vector<StringRef> split_path(const StringRef path)
|
||||
return path_elems;
|
||||
}
|
||||
|
||||
std::optional<Bundle::Item> Bundle::lookup_path(const StringRef path) const
|
||||
const BundleItemValue *Bundle::lookup_path(const StringRef path) const
|
||||
{
|
||||
const Vector<StringRef> path_elems = split_path(path);
|
||||
return this->lookup_path(path_elems);
|
||||
@@ -224,16 +237,21 @@ BundlePtr Bundle::copy() const
|
||||
BundlePtr copy_ptr = Bundle::create();
|
||||
Bundle © = const_cast<Bundle &>(*copy_ptr);
|
||||
for (const StoredItem &item : items_) {
|
||||
copy.add_new(item.key, *item.type, item.value);
|
||||
copy.add_new(item.key, item.value);
|
||||
}
|
||||
return copy_ptr;
|
||||
}
|
||||
|
||||
bool Bundle::remove(const StringRef key)
|
||||
{
|
||||
BLI_assert(is_valid_key(key));
|
||||
const int removed_num = items_.remove_if([&key](StoredItem &item) {
|
||||
if (item.key == key) {
|
||||
item.type->geometry_nodes_cpp_type->destruct(item.value);
|
||||
if (BundleItemSocketValue *socket_value = std::get_if<BundleItemSocketValue>(
|
||||
&item.value.value))
|
||||
{
|
||||
socket_value->type->geometry_nodes_cpp_type->destruct(socket_value->value);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -243,6 +261,7 @@ bool Bundle::remove(const StringRef key)
|
||||
|
||||
bool Bundle::contains(const StringRef key) const
|
||||
{
|
||||
BLI_assert(is_valid_key(key));
|
||||
for (const StoredItem &item : items_) {
|
||||
if (item.key == key) {
|
||||
return true;
|
||||
@@ -253,7 +272,12 @@ bool Bundle::contains(const StringRef key) const
|
||||
|
||||
bool Bundle::contains_path(const StringRef path) const
|
||||
{
|
||||
return this->lookup_path(path).has_value();
|
||||
return this->lookup_path(path) != nullptr;
|
||||
}
|
||||
|
||||
std::string Bundle::combine_path(const Span<StringRef> path)
|
||||
{
|
||||
return fmt::format("{}", fmt::join(path, "/"));
|
||||
}
|
||||
|
||||
void Bundle::delete_self()
|
||||
|
||||
@@ -331,7 +331,16 @@ void GeoTreeLogger::log_value(const bNode &node, const bNodeSocket &socket, cons
|
||||
Vector<BundleValueLog::Item> items;
|
||||
if (const BundlePtr bundle = value_variant.extract<BundlePtr>()) {
|
||||
for (const Bundle::StoredItem &item : bundle->items()) {
|
||||
items.append({item.key, item.type});
|
||||
if (const BundleItemSocketValue *socket_value = std::get_if<BundleItemSocketValue>(
|
||||
&item.value.value))
|
||||
{
|
||||
items.append({item.key, {socket_value->type}});
|
||||
}
|
||||
if (const BundleItemInternalValue *internal_value = std::get_if<BundleItemInternalValue>(
|
||||
&item.value.value))
|
||||
{
|
||||
items.append({item.key, {internal_value->value->type_name()}});
|
||||
}
|
||||
}
|
||||
}
|
||||
store_logged_value(this->allocator->construct<BundleValueLog>(std::move(items)));
|
||||
|
||||
Reference in New Issue
Block a user