Geometry Nodes: deduplicate code to deal with dynamic socket amounts #113114
|
@ -1802,7 +1802,6 @@ typedef struct NodeGeometrySimulationOutput {
|
|||
#ifdef __cplusplus
|
||||
blender::Span<NodeSimulationItem> items_span() const;
|
||||
blender::MutableSpan<NodeSimulationItem> items_span();
|
||||
blender::IndexRange items_range() const;
|
||||
#endif
|
||||
} NodeGeometrySimulationOutput;
|
||||
|
||||
|
@ -1816,11 +1815,6 @@ typedef struct NodeRepeatItem {
|
|||
* names change.
|
||||
*/
|
||||
int identifier;
|
||||
|
||||
#ifdef __cplusplus
|
||||
static bool supports_type(eNodeSocketDatatype type);
|
||||
std::string identifier_str() const;
|
||||
#endif
|
||||
} NodeRepeatItem;
|
||||
|
||||
typedef struct NodeGeometryRepeatInput {
|
||||
|
@ -1839,8 +1833,6 @@ typedef struct NodeGeometryRepeatOutput {
|
|||
#ifdef __cplusplus
|
||||
blender::Span<NodeRepeatItem> items_span() const;
|
||||
blender::MutableSpan<NodeRepeatItem> items_span();
|
||||
NodeRepeatItem *add_item(const char *name, eNodeSocketDatatype type);
|
||||
void set_item_name(NodeRepeatItem &item, const char *name);
|
||||
#endif
|
||||
} NodeGeometryRepeatOutput;
|
||||
|
||||
|
|
|
@ -11,7 +11,9 @@
|
|||
#include <cstring>
|
||||
|
||||
#include "BLI_function_ref.hh"
|
||||
#include "BLI_linear_allocator.hh"
|
||||
#include "BLI_math_rotation.h"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_string_utf8_symbols.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
|
@ -596,7 +598,9 @@ static const EnumPropertyItem node_cryptomatte_layer_name_items[] = {
|
|||
# include "NOD_geometry.hh"
|
||||
# include "NOD_shader.h"
|
||||
# include "NOD_socket.hh"
|
||||
# include "NOD_socket_items.hh"
|
||||
# include "NOD_texture.h"
|
||||
# include "NOD_zone_socket_items.hh"
|
||||
|
||||
# include "RE_engine.h"
|
||||
# include "RE_pipeline.h"
|
||||
|
@ -604,6 +608,9 @@ static const EnumPropertyItem node_cryptomatte_layer_name_items[] = {
|
|||
# include "DNA_scene_types.h"
|
||||
# include "WM_api.hh"
|
||||
|
||||
using blender::nodes::RepeatItemsAccessor;
|
||||
using blender::nodes::SimulationItemsAccessor;
|
||||
|
||||
extern FunctionRNA rna_NodeTree_poll_func;
|
||||
extern FunctionRNA rna_NodeTree_update_func;
|
||||
extern FunctionRNA rna_NodeTree_get_from_context_func;
|
||||
|
@ -3122,105 +3129,6 @@ static void rna_NodeCryptomatte_update_remove(Main *bmain, Scene *scene, Pointer
|
|||
rna_Node_update(bmain, scene, ptr);
|
||||
}
|
||||
|
||||
static void rna_SimulationStateItem_update(Main *bmain, Scene * /*scene*/, PointerRNA *ptr)
|
||||
{
|
||||
bNodeTree *ntree = reinterpret_cast<bNodeTree *>(ptr->owner_id);
|
||||
NodeSimulationItem *item = static_cast<NodeSimulationItem *>(ptr->data);
|
||||
bNode *node = NOD_geometry_simulation_output_find_node_by_item(ntree, item);
|
||||
|
||||
BKE_ntree_update_tag_node_property(ntree, node);
|
||||
ED_node_tree_propagate_change(nullptr, bmain, ntree);
|
||||
}
|
||||
|
||||
static bNode *find_node_by_repeat_item(PointerRNA *ptr)
|
||||
{
|
||||
const NodeRepeatItem *item = static_cast<const NodeRepeatItem *>(ptr->data);
|
||||
bNodeTree *ntree = reinterpret_cast<bNodeTree *>(ptr->owner_id);
|
||||
ntree->ensure_topology_cache();
|
||||
for (bNode *node : ntree->nodes_by_type("GeometryNodeRepeatOutput")) {
|
||||
NodeGeometryRepeatOutput *storage = static_cast<NodeGeometryRepeatOutput *>(node->storage);
|
||||
if (storage->items_span().contains_ptr(item)) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void rna_RepeatItem_update(Main *bmain, Scene * /*scene*/, PointerRNA *ptr)
|
||||
{
|
||||
bNodeTree *ntree = reinterpret_cast<bNodeTree *>(ptr->owner_id);
|
||||
bNode *node = find_node_by_repeat_item(ptr);
|
||||
|
||||
BKE_ntree_update_tag_node_property(ntree, node);
|
||||
ED_node_tree_propagate_change(nullptr, bmain, ntree);
|
||||
}
|
||||
|
||||
static bool rna_SimulationStateItem_socket_type_supported(const EnumPropertyItem *item)
|
||||
{
|
||||
return NOD_geometry_simulation_output_item_socket_type_supported(
|
||||
(eNodeSocketDatatype)item->value);
|
||||
}
|
||||
|
||||
static const EnumPropertyItem *rna_SimulationStateItem_socket_type_itemf(bContext * /*C*/,
|
||||
PointerRNA * /*ptr*/,
|
||||
PropertyRNA * /*prop*/,
|
||||
bool *r_free)
|
||||
{
|
||||
*r_free = true;
|
||||
return itemf_function_check(rna_enum_node_socket_data_type_items,
|
||||
rna_SimulationStateItem_socket_type_supported);
|
||||
}
|
||||
|
||||
static bool rna_RepeatItem_socket_type_supported(const EnumPropertyItem *item)
|
||||
{
|
||||
return NodeRepeatItem::supports_type(eNodeSocketDatatype(item->value));
|
||||
}
|
||||
|
||||
static const EnumPropertyItem *rna_RepeatItem_socket_type_itemf(bContext * /*C*/,
|
||||
PointerRNA * /*ptr*/,
|
||||
PropertyRNA * /*prop*/,
|
||||
bool *r_free)
|
||||
{
|
||||
*r_free = true;
|
||||
return itemf_function_check(rna_enum_node_socket_data_type_items,
|
||||
rna_RepeatItem_socket_type_supported);
|
||||
}
|
||||
|
||||
static void rna_SimulationStateItem_name_set(PointerRNA *ptr, const char *value)
|
||||
{
|
||||
bNodeTree *ntree = reinterpret_cast<bNodeTree *>(ptr->owner_id);
|
||||
NodeSimulationItem *item = static_cast<NodeSimulationItem *>(ptr->data);
|
||||
bNode *node = NOD_geometry_simulation_output_find_node_by_item(ntree, item);
|
||||
NodeGeometrySimulationOutput *sim = static_cast<NodeGeometrySimulationOutput *>(node->storage);
|
||||
|
||||
const char *defname = nodeStaticSocketLabel(item->socket_type, 0);
|
||||
NOD_geometry_simulation_output_item_set_unique_name(sim, item, value, defname);
|
||||
}
|
||||
|
||||
static void rna_RepeatItem_name_set(PointerRNA *ptr, const char *value)
|
||||
{
|
||||
bNode *node = find_node_by_repeat_item(ptr);
|
||||
NodeRepeatItem *item = static_cast<NodeRepeatItem *>(ptr->data);
|
||||
NodeGeometryRepeatOutput *storage = static_cast<NodeGeometryRepeatOutput *>(node->storage);
|
||||
storage->set_item_name(*item, value);
|
||||
}
|
||||
|
||||
static void rna_SimulationStateItem_color_get(PointerRNA *ptr, float *values)
|
||||
{
|
||||
NodeSimulationItem *item = static_cast<NodeSimulationItem *>(ptr->data);
|
||||
|
||||
const char *socket_type_idname = nodeStaticSocketType(item->socket_type, 0);
|
||||
ED_node_type_draw_color(socket_type_idname, values);
|
||||
}
|
||||
|
||||
static void rna_RepeatItem_color_get(PointerRNA *ptr, float *values)
|
||||
{
|
||||
NodeRepeatItem *item = static_cast<NodeRepeatItem *>(ptr->data);
|
||||
|
||||
const char *socket_type_idname = nodeStaticSocketType(item->socket_type, 0);
|
||||
ED_node_type_draw_color(socket_type_idname, values);
|
||||
}
|
||||
|
||||
static PointerRNA rna_Node_paired_output_get(PointerRNA *ptr)
|
||||
{
|
||||
bNodeTree *ntree = reinterpret_cast<bNodeTree *>(ptr->owner_id);
|
||||
|
@ -3266,200 +3174,148 @@ static bool rna_Node_pair_with_output(
|
|||
return true;
|
||||
}
|
||||
|
||||
static NodeSimulationItem *rna_NodeGeometrySimulationOutput_items_new(
|
||||
template<typename Accessor>
|
||||
static void rna_Node_ItemArray_remove(ID *id,
|
||||
bNode *node,
|
||||
Main *bmain,
|
||||
ReportList *reports,
|
||||
typename Accessor::ItemT *item_to_remove)
|
||||
{
|
||||
blender::nodes::socket_items::SocketItemsRef ref = Accessor::get_items_from_node(*node);
|
||||
if (item_to_remove < *ref.items || item_to_remove >= *ref.items + *ref.items_num) {
|
||||
BKE_reportf(reports, RPT_ERROR, "Unable to locate item '%s' in node", item_to_remove->name);
|
||||
return;
|
||||
}
|
||||
const int remove_index = item_to_remove - *ref.items;
|
||||
blender::nodes::socket_items::remove_item(
|
||||
ref.items, ref.items_num, ref.active_index, remove_index, Accessor::destruct_item);
|
||||
|
||||
bNodeTree *ntree = reinterpret_cast<bNodeTree *>(id);
|
||||
BKE_ntree_update_tag_node_property(ntree, node);
|
||||
ED_node_tree_propagate_change(nullptr, bmain, ntree);
|
||||
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
|
||||
}
|
||||
|
||||
template<typename Accessor> static void rna_Node_ItemArray_clear(ID *id, bNode *node, Main *bmain)
|
||||
{
|
||||
blender::nodes::socket_items::SocketItemsRef ref = Accessor::get_items_from_node(*node);
|
||||
blender::nodes::socket_items::clear_items(
|
||||
ref.items, ref.items_num, ref.active_index, Accessor::destruct_item);
|
||||
|
||||
bNodeTree *ntree = reinterpret_cast<bNodeTree *>(id);
|
||||
BKE_ntree_update_tag_node_property(ntree, node);
|
||||
ED_node_tree_propagate_change(nullptr, bmain, ntree);
|
||||
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
|
||||
}
|
||||
|
||||
template<typename Accessor>
|
||||
static void rna_Node_ItemArray_move(
|
||||
ID *id, bNode *node, Main *bmain, const int from_index, const int to_index)
|
||||
{
|
||||
blender::nodes::socket_items::SocketItemsRef ref = Accessor::get_items_from_node(*node);
|
||||
const int items_num = *ref.items_num;
|
||||
if (from_index < 0 || to_index < 0 || from_index >= items_num || to_index >= items_num) {
|
||||
return;
|
||||
}
|
||||
blender::nodes::socket_items::move_item(*ref.items, items_num, from_index, to_index);
|
||||
|
||||
bNodeTree *ntree = reinterpret_cast<bNodeTree *>(id);
|
||||
BKE_ntree_update_tag_node_property(ntree, node);
|
||||
ED_node_tree_propagate_change(nullptr, bmain, ntree);
|
||||
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
|
||||
}
|
||||
|
||||
template<typename Accessor> static PointerRNA rna_Node_ItemArray_active_get(PointerRNA *ptr)
|
||||
{
|
||||
bNode *node = static_cast<bNode *>(ptr->data);
|
||||
blender::nodes::socket_items::SocketItemsRef ref = Accessor::get_items_from_node(*node);
|
||||
typename Accessor::ItemT *active_item = nullptr;
|
||||
const int active_index = *ref.active_index;
|
||||
const int items_num = *ref.items_num;
|
||||
if (active_index >= 0 && active_index < items_num) {
|
||||
active_item = &(*ref.items)[active_index];
|
||||
}
|
||||
return RNA_pointer_create(ptr->owner_id, Accessor::item_srna, active_item);
|
||||
}
|
||||
template<typename Accessor>
|
||||
static void rna_Node_ItemArray_active_set(PointerRNA *ptr,
|
||||
PointerRNA value,
|
||||
ReportList * /*reports*/)
|
||||
{
|
||||
using ItemT = typename Accessor::ItemT;
|
||||
bNode *node = static_cast<bNode *>(ptr->data);
|
||||
ItemT *item = static_cast<ItemT *>(value.data);
|
||||
|
||||
blender::nodes::socket_items::SocketItemsRef ref = Accessor::get_items_from_node(*node);
|
||||
if (item >= *ref.items && item < *ref.items + *ref.items_num) {
|
||||
*ref.active_index = item - *ref.items;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Accessor>
|
||||
static void rna_Node_ItemArray_item_update(Main *bmain, Scene * /*scene*/, PointerRNA *ptr)
|
||||
{
|
||||
using ItemT = typename Accessor::ItemT;
|
||||
bNodeTree &ntree = *reinterpret_cast<bNodeTree *>(ptr->owner_id);
|
||||
ItemT &item = *static_cast<ItemT *>(ptr->data);
|
||||
bNode *node = blender::nodes::socket_items::find_node_by_item<Accessor>(ntree, item);
|
||||
BLI_assert(node != nullptr);
|
||||
|
||||
BKE_ntree_update_tag_node_property(&ntree, node);
|
||||
ED_node_tree_propagate_change(nullptr, bmain, &ntree);
|
||||
}
|
||||
|
||||
template<typename Accessor>
|
||||
static const EnumPropertyItem *rna_Node_ItemArray_socket_type_itemf(bContext * /*C*/,
|
||||
PointerRNA * /*ptr*/,
|
||||
PropertyRNA * /*prop*/,
|
||||
bool *r_free)
|
||||
{
|
||||
*r_free = true;
|
||||
return itemf_function_check(
|
||||
rna_enum_node_socket_data_type_items, [](const EnumPropertyItem *item) {
|
||||
return Accessor::supports_socket_type(eNodeSocketDatatype(item->value));
|
||||
});
|
||||
}
|
||||
|
||||
template<typename Accessor>
|
||||
static void rna_Node_ItemArray_item_name_set(PointerRNA *ptr, const char *value)
|
||||
{
|
||||
using ItemT = typename Accessor::ItemT;
|
||||
bNodeTree &ntree = *reinterpret_cast<bNodeTree *>(ptr->owner_id);
|
||||
ItemT &item = *static_cast<ItemT *>(ptr->data);
|
||||
bNode *node = blender::nodes::socket_items::find_node_by_item<Accessor>(ntree, item);
|
||||
BLI_assert(node != nullptr);
|
||||
blender::nodes::socket_items::set_item_name_and_make_unique<Accessor>(*node, item, value);
|
||||
}
|
||||
|
||||
template<typename Accessors>
|
||||
static void rna_Node_ItemArray_item_color_get(PointerRNA *ptr, float *values)
|
||||
{
|
||||
using ItemT = typename Accessors::ItemT;
|
||||
ItemT &item = *static_cast<ItemT *>(ptr->data);
|
||||
const char *socket_type_idname = nodeStaticSocketType(*Accessors::get_socket_type(item), 0);
|
||||
ED_node_type_draw_color(socket_type_idname, values);
|
||||
}
|
||||
|
||||
template<typename Accessor>
|
||||
typename Accessor::ItemT *rna_Node_ItemArray_new_with_socket_and_name(
|
||||
ID *id, bNode *node, Main *bmain, ReportList *reports, int socket_type, const char *name)
|
||||
{
|
||||
NodeGeometrySimulationOutput *sim = static_cast<NodeGeometrySimulationOutput *>(node->storage);
|
||||
NodeSimulationItem *item = NOD_geometry_simulation_output_add_item(
|
||||
sim, short(socket_type), name);
|
||||
|
||||
if (item == nullptr) {
|
||||
BKE_report(reports, RPT_ERROR, "Unable to create socket");
|
||||
using ItemT = typename Accessor::ItemT;
|
||||
if (!Accessor::supports_socket_type(eNodeSocketDatatype(socket_type))) {
|
||||
BKE_report(reports, RPT_ERROR, "Unable to create item with this socket type");
|
||||
return nullptr;
|
||||
}
|
||||
else {
|
||||
bNodeTree *ntree = reinterpret_cast<bNodeTree *>(id);
|
||||
BKE_ntree_update_tag_node_property(ntree, node);
|
||||
ED_node_tree_propagate_change(nullptr, bmain, ntree);
|
||||
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
static NodeRepeatItem *rna_NodeGeometryRepeatOutput_items_new(
|
||||
ID *id, bNode *node, Main *bmain, ReportList *reports, int socket_type, const char *name)
|
||||
{
|
||||
NodeGeometryRepeatOutput *storage = static_cast<NodeGeometryRepeatOutput *>(node->storage);
|
||||
NodeRepeatItem *item = storage->add_item(name, eNodeSocketDatatype(socket_type));
|
||||
if (item == nullptr) {
|
||||
BKE_report(reports, RPT_ERROR, "Unable to create socket");
|
||||
}
|
||||
else {
|
||||
bNodeTree *ntree = reinterpret_cast<bNodeTree *>(id);
|
||||
BKE_ntree_update_tag_node_property(ntree, node);
|
||||
ED_node_tree_propagate_change(nullptr, bmain, ntree);
|
||||
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
static void rna_NodeGeometrySimulationOutput_items_remove(
|
||||
ID *id, bNode *node, Main *bmain, ReportList *reports, NodeSimulationItem *item)
|
||||
{
|
||||
NodeGeometrySimulationOutput *sim = static_cast<NodeGeometrySimulationOutput *>(node->storage);
|
||||
if (!NOD_geometry_simulation_output_contains_item(sim, item)) {
|
||||
BKE_reportf(reports, RPT_ERROR, "Unable to locate item '%s' in node", item->name);
|
||||
}
|
||||
else {
|
||||
NOD_geometry_simulation_output_remove_item(sim, item);
|
||||
|
||||
bNodeTree *ntree = reinterpret_cast<bNodeTree *>(id);
|
||||
BKE_ntree_update_tag_node_property(ntree, node);
|
||||
ED_node_tree_propagate_change(nullptr, bmain, ntree);
|
||||
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
|
||||
}
|
||||
}
|
||||
|
||||
static void rna_NodeGeometryRepeatOutput_items_remove(
|
||||
ID *id, bNode *node, Main *bmain, ReportList *reports, NodeRepeatItem *item)
|
||||
{
|
||||
NodeGeometryRepeatOutput *storage = static_cast<NodeGeometryRepeatOutput *>(node->storage);
|
||||
if (!storage->items_span().contains_ptr(item)) {
|
||||
BKE_reportf(reports, RPT_ERROR, "Unable to locate item '%s' in node", item->name);
|
||||
return;
|
||||
}
|
||||
|
||||
const int remove_index = item - storage->items;
|
||||
NodeRepeatItem *old_items = storage->items;
|
||||
storage->items = MEM_cnew_array<NodeRepeatItem>(storage->items_num - 1, __func__);
|
||||
std::copy_n(old_items, remove_index, storage->items);
|
||||
std::copy_n(old_items + remove_index + 1,
|
||||
storage->items_num - remove_index - 1,
|
||||
storage->items + remove_index);
|
||||
|
||||
MEM_SAFE_FREE(old_items[remove_index].name);
|
||||
storage->items_num--;
|
||||
MEM_SAFE_FREE(old_items);
|
||||
ItemT *new_item = blender::nodes::socket_items::add_item_with_socket_and_name<Accessor>(
|
||||
*node, eNodeSocketDatatype(socket_type), name);
|
||||
|
||||
bNodeTree *ntree = reinterpret_cast<bNodeTree *>(id);
|
||||
BKE_ntree_update_tag_node_property(ntree, node);
|
||||
ED_node_tree_propagate_change(nullptr, bmain, ntree);
|
||||
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
|
||||
}
|
||||
|
||||
static void rna_NodeGeometrySimulationOutput_items_clear(ID *id, bNode *node, Main *bmain)
|
||||
{
|
||||
NodeGeometrySimulationOutput *sim = static_cast<NodeGeometrySimulationOutput *>(node->storage);
|
||||
NOD_geometry_simulation_output_clear_items(sim);
|
||||
|
||||
bNodeTree *ntree = reinterpret_cast<bNodeTree *>(id);
|
||||
BKE_ntree_update_tag_node_property(ntree, node);
|
||||
ED_node_tree_propagate_change(nullptr, bmain, ntree);
|
||||
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
|
||||
}
|
||||
|
||||
static void rna_NodeGeometryRepeatOutput_items_clear(ID * /*id*/, bNode *node, Main * /*bmain*/)
|
||||
{
|
||||
NodeGeometryRepeatOutput *storage = static_cast<NodeGeometryRepeatOutput *>(node->storage);
|
||||
for (NodeRepeatItem &item : storage->items_span()) {
|
||||
MEM_SAFE_FREE(item.name);
|
||||
}
|
||||
MEM_SAFE_FREE(storage->items);
|
||||
storage->items_num = 0;
|
||||
storage->active_index = 0;
|
||||
}
|
||||
|
||||
static void rna_NodeGeometrySimulationOutput_items_move(
|
||||
ID *id, bNode *node, Main *bmain, int from_index, int to_index)
|
||||
{
|
||||
NodeGeometrySimulationOutput *sim = static_cast<NodeGeometrySimulationOutput *>(node->storage);
|
||||
|
||||
if (from_index < 0 || from_index >= sim->items_num || to_index < 0 || to_index >= sim->items_num)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
NOD_geometry_simulation_output_move_item(sim, from_index, to_index);
|
||||
|
||||
bNodeTree *ntree = reinterpret_cast<bNodeTree *>(id);
|
||||
BKE_ntree_update_tag_node_property(ntree, node);
|
||||
ED_node_tree_propagate_change(nullptr, bmain, ntree);
|
||||
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
|
||||
}
|
||||
|
||||
static void rna_NodeGeometryRepeatOutput_items_move(
|
||||
ID *id, bNode *node, Main *bmain, int from_index, int to_index)
|
||||
{
|
||||
NodeGeometryRepeatOutput *storage = static_cast<NodeGeometryRepeatOutput *>(node->storage);
|
||||
if (from_index < 0 || from_index >= storage->items_num || to_index < 0 ||
|
||||
to_index >= storage->items_num)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (from_index < to_index) {
|
||||
const NodeRepeatItem tmp = storage->items[from_index];
|
||||
for (int i = from_index; i < to_index; i++) {
|
||||
storage->items[i] = storage->items[i + 1];
|
||||
}
|
||||
storage->items[to_index] = tmp;
|
||||
}
|
||||
else if (from_index > to_index) {
|
||||
const NodeRepeatItem tmp = storage->items[from_index];
|
||||
for (int i = from_index; i > to_index; i--) {
|
||||
storage->items[i] = storage->items[i - 1];
|
||||
}
|
||||
storage->items[to_index] = tmp;
|
||||
}
|
||||
|
||||
bNodeTree *ntree = reinterpret_cast<bNodeTree *>(id);
|
||||
BKE_ntree_update_tag_node_property(ntree, node);
|
||||
ED_node_tree_propagate_change(nullptr, bmain, ntree);
|
||||
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
|
||||
}
|
||||
|
||||
static PointerRNA rna_NodeGeometrySimulationOutput_active_item_get(PointerRNA *ptr)
|
||||
{
|
||||
bNode *node = static_cast<bNode *>(ptr->data);
|
||||
NodeGeometrySimulationOutput *sim = static_cast<NodeGeometrySimulationOutput *>(node->storage);
|
||||
NodeSimulationItem *item = NOD_geometry_simulation_output_get_active_item(sim);
|
||||
PointerRNA r_ptr = RNA_pointer_create(ptr->owner_id, &RNA_SimulationStateItem, item);
|
||||
return r_ptr;
|
||||
}
|
||||
|
||||
static PointerRNA rna_NodeGeometryRepeatOutput_active_item_get(PointerRNA *ptr)
|
||||
{
|
||||
bNode *node = static_cast<bNode *>(ptr->data);
|
||||
NodeGeometryRepeatOutput *storage = static_cast<NodeGeometryRepeatOutput *>(node->storage);
|
||||
blender::MutableSpan<NodeRepeatItem> items = storage->items_span();
|
||||
PointerRNA r_ptr{};
|
||||
if (items.index_range().contains(storage->active_index)) {
|
||||
r_ptr = RNA_pointer_create(ptr->owner_id, &RNA_RepeatItem, &items[storage->active_index]);
|
||||
}
|
||||
return r_ptr;
|
||||
}
|
||||
|
||||
static void rna_NodeGeometrySimulationOutput_active_item_set(PointerRNA *ptr,
|
||||
PointerRNA value,
|
||||
ReportList * /*reports*/)
|
||||
{
|
||||
bNode *node = static_cast<bNode *>(ptr->data);
|
||||
NodeGeometrySimulationOutput *sim = static_cast<NodeGeometrySimulationOutput *>(node->storage);
|
||||
NOD_geometry_simulation_output_set_active_item(sim,
|
||||
static_cast<NodeSimulationItem *>(value.data));
|
||||
}
|
||||
|
||||
static void rna_NodeGeometryRepeatOutput_active_item_set(PointerRNA *ptr,
|
||||
PointerRNA value,
|
||||
ReportList * /*reports*/)
|
||||
{
|
||||
bNode *node = static_cast<bNode *>(ptr->data);
|
||||
NodeGeometryRepeatOutput *storage = static_cast<NodeGeometryRepeatOutput *>(node->storage);
|
||||
NodeRepeatItem *item = static_cast<NodeRepeatItem *>(value.data);
|
||||
if (storage->items_span().contains_ptr(item)) {
|
||||
storage->active_index = item - storage->items;
|
||||
}
|
||||
return new_item;
|
||||
}
|
||||
|
||||
/* ******** Node Socket Types ******** */
|
||||
|
@ -8869,56 +8725,98 @@ static void def_geo_repeat_input(StructRNA *srna)
|
|||
def_common_zone_input(srna);
|
||||
}
|
||||
|
||||
static void rna_def_simulation_state_item(BlenderRNA *brna)
|
||||
static void rna_def_node_item_array_socket_item_common(StructRNA *srna,
|
||||
const char *accessor,
|
||||
blender::LinearAllocator<> &allocator)
|
||||
{
|
||||
PropertyRNA *prop;
|
||||
|
||||
StructRNA *srna = RNA_def_struct(brna, "SimulationStateItem", nullptr);
|
||||
RNA_def_struct_ui_text(srna, "Simulation Item", "");
|
||||
RNA_def_struct_sdna(srna, "NodeSimulationItem");
|
||||
char name_set_func[64];
|
||||
SNPRINTF(name_set_func, "rna_Node_ItemArray_item_name_set<%s>", accessor);
|
||||
|
||||
char item_update_func[64];
|
||||
SNPRINTF(item_update_func, "rna_Node_ItemArray_item_update<%s>", accessor);
|
||||
const char *item_update_func_ptr = allocator.copy_string(item_update_func).c_str();
|
||||
|
||||
char socket_type_itemf[64];
|
||||
SNPRINTF(socket_type_itemf, "rna_Node_ItemArray_socket_type_itemf<%s>", accessor);
|
||||
|
||||
char color_get_func[64];
|
||||
SNPRINTF(color_get_func, "rna_Node_ItemArray_item_color_get<%s>", accessor);
|
||||
|
||||
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_string_funcs(prop, nullptr, nullptr, "rna_SimulationStateItem_name_set");
|
||||
RNA_def_property_string_funcs(
|
||||
prop, nullptr, nullptr, allocator.copy_string(name_set_func).c_str());
|
||||
RNA_def_property_ui_text(prop, "Name", "");
|
||||
RNA_def_struct_name_property(srna, prop);
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_SimulationStateItem_update");
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, item_update_func_ptr);
|
||||
|
||||
prop = RNA_def_property(srna, "socket_type", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, rna_enum_node_socket_data_type_items);
|
||||
RNA_def_property_enum_funcs(prop, nullptr, nullptr, "rna_SimulationStateItem_socket_type_itemf");
|
||||
RNA_def_property_enum_funcs(
|
||||
prop, nullptr, nullptr, allocator.copy_string(socket_type_itemf).c_str());
|
||||
RNA_def_property_ui_text(prop, "Socket Type", "");
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_SimulationStateItem_update");
|
||||
|
||||
prop = RNA_def_property(srna, "attribute_domain", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, rna_enum_attribute_domain_items);
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Attribute Domain",
|
||||
"Attribute domain where the attribute is stored in the simulation state");
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_SimulationStateItem_update");
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, item_update_func_ptr);
|
||||
|
||||
prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA);
|
||||
RNA_def_property_array(prop, 4);
|
||||
RNA_def_property_float_funcs(prop, "rna_SimulationStateItem_color_get", nullptr, nullptr);
|
||||
RNA_def_property_float_funcs(
|
||||
prop, allocator.copy_string(color_get_func).c_str(), nullptr, nullptr);
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Color", "Color of the corresponding socket type in the node editor");
|
||||
}
|
||||
|
||||
static void rna_def_geo_simulation_output_items(BlenderRNA *brna)
|
||||
static void rna_def_node_item_array_common_functions(StructRNA *srna,
|
||||
const char *item_name,
|
||||
const char *accessor_name,
|
||||
blender::LinearAllocator<> &allocator)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *parm;
|
||||
FunctionRNA *func;
|
||||
|
||||
srna = RNA_def_struct(brna, "NodeGeometrySimulationOutputItems", nullptr);
|
||||
RNA_def_struct_sdna(srna, "bNode");
|
||||
RNA_def_struct_ui_text(srna, "Items", "Collection of simulation items");
|
||||
char remove_call[64];
|
||||
SNPRINTF(remove_call, "rna_Node_ItemArray_remove<%s>", accessor_name);
|
||||
char clear_call[64];
|
||||
SNPRINTF(clear_call, "rna_Node_ItemArray_clear<%s>", accessor_name);
|
||||
char move_call[64];
|
||||
SNPRINTF(move_call, "rna_Node_ItemArray_move<%s>", accessor_name);
|
||||
|
||||
func = RNA_def_function(srna, "new", "rna_NodeGeometrySimulationOutput_items_new");
|
||||
RNA_def_function_ui_description(func, "Add a item to this simulation zone");
|
||||
func = RNA_def_function(srna, "remove", allocator.copy_string(remove_call).c_str());
|
||||
RNA_def_function_ui_description(func, "Remove an item");
|
||||
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS);
|
||||
parm = RNA_def_pointer(func, "item", item_name, "Item", "The item to remove");
|
||||
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
|
||||
|
||||
func = RNA_def_function(srna, "clear", allocator.copy_string(clear_call).c_str());
|
||||
RNA_def_function_ui_description(func, "Remove all items");
|
||||
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN);
|
||||
|
||||
func = RNA_def_function(srna, "move", allocator.copy_string(move_call).c_str());
|
||||
RNA_def_function_ui_description(func, "Move an item to another position");
|
||||
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN);
|
||||
parm = RNA_def_int(
|
||||
func, "from_index", -1, 0, INT_MAX, "From Index", "Index of the item to move", 0, 10000);
|
||||
RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED);
|
||||
parm = RNA_def_int(
|
||||
func, "to_index", -1, 0, INT_MAX, "To Index", "Target index for the item", 0, 10000);
|
||||
RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED);
|
||||
}
|
||||
|
||||
static void rna_def_node_item_array_new_with_socket_and_name(StructRNA *srna,
|
||||
const char *item_name,
|
||||
const char *accessor_name,
|
||||
blender::LinearAllocator<> &allocator)
|
||||
{
|
||||
PropertyRNA *parm;
|
||||
FunctionRNA *func;
|
||||
JacquesLucke marked this conversation as resolved
Outdated
|
||||
|
||||
char name[128];
|
||||
SNPRINTF(name, "rna_Node_ItemArray_new_with_socket_and_name<%s>", accessor_name);
|
||||
|
||||
func = RNA_def_function(srna, "new", allocator.copy_string(name).c_str());
|
||||
RNA_def_function_ui_description(func, "Add an item at the end");
|
||||
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS);
|
||||
parm = RNA_def_enum(func,
|
||||
"socket_type",
|
||||
|
@ -8930,28 +8828,45 @@ static void rna_def_geo_simulation_output_items(BlenderRNA *brna)
|
|||
parm = RNA_def_string(func, "name", nullptr, MAX_NAME, "Name", "");
|
||||
RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED);
|
||||
/* return value */
|
||||
parm = RNA_def_pointer(func, "item", "SimulationStateItem", "Item", "New item");
|
||||
parm = RNA_def_pointer(func, "item", item_name, "Item", "New item");
|
||||
RNA_def_function_return(func, parm);
|
||||
}
|
||||
|
||||
func = RNA_def_function(srna, "remove", "rna_NodeGeometrySimulationOutput_items_remove");
|
||||
RNA_def_function_ui_description(func, "Remove an item from this simulation zone");
|
||||
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS);
|
||||
parm = RNA_def_pointer(func, "item", "SimulationStateItem", "Item", "The item to remove");
|
||||
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
|
||||
static void rna_def_simulation_state_item(BlenderRNA *brna)
|
||||
{
|
||||
PropertyRNA *prop;
|
||||
static blender::LinearAllocator<> allocator;
|
||||
|
||||
func = RNA_def_function(srna, "clear", "rna_NodeGeometrySimulationOutput_items_clear");
|
||||
RNA_def_function_ui_description(func, "Remove all items from this simulation zone");
|
||||
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN);
|
||||
StructRNA *srna = RNA_def_struct(brna, "SimulationStateItem", nullptr);
|
||||
RNA_def_struct_ui_text(srna, "Simulation Item", "");
|
||||
RNA_def_struct_sdna(srna, "NodeSimulationItem");
|
||||
|
||||
func = RNA_def_function(srna, "move", "rna_NodeGeometrySimulationOutput_items_move");
|
||||
RNA_def_function_ui_description(func, "Move an item to another position");
|
||||
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN);
|
||||
parm = RNA_def_int(
|
||||
func, "from_index", -1, 0, INT_MAX, "From Index", "Index of the item to move", 0, 10000);
|
||||
RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED);
|
||||
parm = RNA_def_int(
|
||||
func, "to_index", -1, 0, INT_MAX, "To Index", "Target index for the item", 0, 10000);
|
||||
RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED);
|
||||
rna_def_node_item_array_socket_item_common(srna, "SimulationItemsAccessor", allocator);
|
||||
|
||||
prop = RNA_def_property(srna, "attribute_domain", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, rna_enum_attribute_domain_items);
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Attribute Domain",
|
||||
"Attribute domain where the attribute is stored in the simulation state");
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_update(
|
||||
prop, NC_NODE | NA_EDITED, "rna_Node_ItemArray_item_update<SimulationItemsAccessor>");
|
||||
}
|
||||
|
||||
static void rna_def_geo_simulation_output_items(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
static blender::LinearAllocator<> allocator;
|
||||
|
||||
srna = RNA_def_struct(brna, "NodeGeometrySimulationOutputItems", nullptr);
|
||||
RNA_def_struct_sdna(srna, "bNode");
|
||||
RNA_def_struct_ui_text(srna, "Items", "Collection of simulation items");
|
||||
|
||||
rna_def_node_item_array_new_with_socket_and_name(
|
||||
srna, "SimulationStateItem", "SimulationItemsAccessor", allocator);
|
||||
rna_def_node_item_array_common_functions(
|
||||
srna, "SimulationStateItem", "SimulationItemsAccessor", allocator);
|
||||
}
|
||||
|
||||
static void def_geo_simulation_output(StructRNA *srna)
|
||||
|
@ -8976,8 +8891,8 @@ static void def_geo_simulation_output(StructRNA *srna)
|
|||
prop = RNA_def_property(srna, "active_item", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "SimulationStateItem");
|
||||
RNA_def_property_pointer_funcs(prop,
|
||||
"rna_NodeGeometrySimulationOutput_active_item_get",
|
||||
"rna_NodeGeometrySimulationOutput_active_item_set",
|
||||
"rna_Node_ItemArray_active_get<SimulationItemsAccessor>",
|
||||
"rna_Node_ItemArray_active_set<SimulationItemsAccessor>",
|
||||
nullptr,
|
||||
nullptr);
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NO_DEG_UPDATE);
|
||||
|
@ -8987,78 +8902,27 @@ static void def_geo_simulation_output(StructRNA *srna)
|
|||
|
||||
static void rna_def_repeat_item(BlenderRNA *brna)
|
||||
{
|
||||
PropertyRNA *prop;
|
||||
static blender::LinearAllocator<> allocator;
|
||||
|
||||
StructRNA *srna = RNA_def_struct(brna, "RepeatItem", nullptr);
|
||||
RNA_def_struct_ui_text(srna, "Repeat Item", "");
|
||||
RNA_def_struct_sdna(srna, "NodeRepeatItem");
|
||||
|
||||
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_string_funcs(prop, nullptr, nullptr, "rna_RepeatItem_name_set");
|
||||
RNA_def_property_ui_text(prop, "Name", "");
|
||||
RNA_def_struct_name_property(srna, prop);
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_RepeatItem_update");
|
||||
|
||||
prop = RNA_def_property(srna, "socket_type", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, rna_enum_node_socket_data_type_items);
|
||||
RNA_def_property_enum_funcs(prop, nullptr, nullptr, "rna_RepeatItem_socket_type_itemf");
|
||||
RNA_def_property_ui_text(prop, "Socket Type", "");
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_RepeatItem_update");
|
||||
|
||||
prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA);
|
||||
RNA_def_property_array(prop, 4);
|
||||
RNA_def_property_float_funcs(prop, "rna_RepeatItem_color_get", nullptr, nullptr);
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Color", "Color of the corresponding socket type in the node editor");
|
||||
rna_def_node_item_array_socket_item_common(srna, "RepeatItemsAccessor", allocator);
|
||||
}
|
||||
|
||||
static void rna_def_geo_repeat_output_items(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *parm;
|
||||
FunctionRNA *func;
|
||||
static blender::LinearAllocator<> allocator;
|
||||
|
||||
srna = RNA_def_struct(brna, "NodeGeometryRepeatOutputItems", nullptr);
|
||||
RNA_def_struct_sdna(srna, "bNode");
|
||||
RNA_def_struct_ui_text(srna, "Items", "Collection of repeat items");
|
||||
|
||||
func = RNA_def_function(srna, "new", "rna_NodeGeometryRepeatOutput_items_new");
|
||||
RNA_def_function_ui_description(func, "Add a item to this repeat zone");
|
||||
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS);
|
||||
parm = RNA_def_enum(func,
|
||||
"socket_type",
|
||||
rna_enum_node_socket_data_type_items,
|
||||
SOCK_GEOMETRY,
|
||||
"Socket Type",
|
||||
"Socket type of the item");
|
||||
RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED);
|
||||
parm = RNA_def_string(func, "name", nullptr, MAX_NAME, "Name", "");
|
||||
RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED);
|
||||
/* return value */
|
||||
parm = RNA_def_pointer(func, "item", "RepeatItem", "Item", "New item");
|
||||
RNA_def_function_return(func, parm);
|
||||
|
||||
func = RNA_def_function(srna, "remove", "rna_NodeGeometryRepeatOutput_items_remove");
|
||||
RNA_def_function_ui_description(func, "Remove an item from this repeat zone");
|
||||
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS);
|
||||
parm = RNA_def_pointer(func, "item", "RepeatItem", "Item", "The item to remove");
|
||||
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
|
||||
|
||||
func = RNA_def_function(srna, "clear", "rna_NodeGeometryRepeatOutput_items_clear");
|
||||
RNA_def_function_ui_description(func, "Remove all items from this repeat zone");
|
||||
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN);
|
||||
|
||||
func = RNA_def_function(srna, "move", "rna_NodeGeometryRepeatOutput_items_move");
|
||||
RNA_def_function_ui_description(func, "Move an item to another position");
|
||||
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN);
|
||||
parm = RNA_def_int(
|
||||
func, "from_index", -1, 0, INT_MAX, "From Index", "Index of the item to move", 0, 10000);
|
||||
RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED);
|
||||
parm = RNA_def_int(
|
||||
func, "to_index", -1, 0, INT_MAX, "To Index", "Target index for the item", 0, 10000);
|
||||
RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED);
|
||||
rna_def_node_item_array_new_with_socket_and_name(
|
||||
srna, "RepeatItem", "RepeatItemsAccessor", allocator);
|
||||
rna_def_node_item_array_common_functions(srna, "RepeatItem", "RepeatItemsAccessor", allocator);
|
||||
}
|
||||
|
||||
static void def_geo_repeat_output(StructRNA *srna)
|
||||
|
@ -9083,8 +8947,8 @@ static void def_geo_repeat_output(StructRNA *srna)
|
|||
prop = RNA_def_property(srna, "active_item", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "RepeatItem");
|
||||
RNA_def_property_pointer_funcs(prop,
|
||||
"rna_NodeGeometryRepeatOutput_active_item_get",
|
||||
"rna_NodeGeometryRepeatOutput_active_item_set",
|
||||
"rna_Node_ItemArray_active_get<RepeatItemsAccessor>",
|
||||
"rna_Node_ItemArray_active_set<RepeatItemsAccessor>",
|
||||
nullptr,
|
||||
nullptr);
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NO_DEG_UPDATE);
|
||||
|
|
|
@ -91,6 +91,7 @@ set(SRC
|
|||
intern/node_socket.cc
|
||||
intern/node_socket_declarations.cc
|
||||
intern/node_util.cc
|
||||
intern/node_zone_socket_items.cc
|
||||
intern/socket_search_link.cc
|
||||
|
||||
NOD_common.h
|
||||
|
@ -101,6 +102,7 @@ set(SRC
|
|||
NOD_geometry_nodes_execute.hh
|
||||
NOD_geometry_nodes_lazy_function.hh
|
||||
NOD_geometry_nodes_log.hh
|
||||
NOD_socket_items.hh
|
||||
NOD_math_functions.hh
|
||||
NOD_multi_function.hh
|
||||
NOD_node_declaration.hh
|
||||
|
@ -113,6 +115,7 @@ set(SRC
|
|||
NOD_socket_search_link.hh
|
||||
NOD_static_types.h
|
||||
NOD_texture.h
|
||||
NOD_zone_socket_items.hh
|
||||
intern/node_common.h
|
||||
intern/node_exec.hh
|
||||
intern/node_util.hh
|
||||
|
|
|
@ -10,55 +10,3 @@ extern bNodeTreeType *ntreeType_Geometry;
|
|||
|
||||
void register_node_tree_type_geo();
|
||||
void register_node_type_geo_custom_group(bNodeType *ntype);
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Simulation Output Node
|
||||
* \{ */
|
||||
|
||||
bool NOD_geometry_simulation_output_item_socket_type_supported(eNodeSocketDatatype socket_type);
|
||||
|
||||
/**
|
||||
* Set a unique item name.
|
||||
* \return True if the unique name differs from the original name.
|
||||
*/
|
||||
bool NOD_geometry_simulation_output_item_set_unique_name(NodeGeometrySimulationOutput *sim,
|
||||
NodeSimulationItem *item,
|
||||
const char *name,
|
||||
const char *defname);
|
||||
|
||||
/**
|
||||
* Find the node owning this simulation state item.
|
||||
*/
|
||||
bNode *NOD_geometry_simulation_output_find_node_by_item(bNodeTree *ntree,
|
||||
const NodeSimulationItem *item);
|
||||
|
||||
bool NOD_geometry_simulation_output_contains_item(NodeGeometrySimulationOutput *sim,
|
||||
const NodeSimulationItem *item);
|
||||
NodeSimulationItem *NOD_geometry_simulation_output_get_active_item(
|
||||
NodeGeometrySimulationOutput *sim);
|
||||
void NOD_geometry_simulation_output_set_active_item(NodeGeometrySimulationOutput *sim,
|
||||
NodeSimulationItem *item);
|
||||
NodeSimulationItem *NOD_geometry_simulation_output_find_item(NodeGeometrySimulationOutput *sim,
|
||||
const char *name);
|
||||
NodeSimulationItem *NOD_geometry_simulation_output_add_item(NodeGeometrySimulationOutput *sim,
|
||||
short socket_type,
|
||||
const char *name);
|
||||
NodeSimulationItem *NOD_geometry_simulation_output_insert_item(NodeGeometrySimulationOutput *sim,
|
||||
short socket_type,
|
||||
const char *name,
|
||||
int index);
|
||||
NodeSimulationItem *NOD_geometry_simulation_output_add_item_from_socket(
|
||||
NodeGeometrySimulationOutput *sim, const bNode *from_node, const bNodeSocket *from_sock);
|
||||
NodeSimulationItem *NOD_geometry_simulation_output_insert_item_from_socket(
|
||||
NodeGeometrySimulationOutput *sim,
|
||||
const bNode *from_node,
|
||||
const bNodeSocket *from_sock,
|
||||
int index);
|
||||
void NOD_geometry_simulation_output_remove_item(NodeGeometrySimulationOutput *sim,
|
||||
NodeSimulationItem *item);
|
||||
void NOD_geometry_simulation_output_clear_items(NodeGeometrySimulationOutput *sim);
|
||||
void NOD_geometry_simulation_output_move_item(NodeGeometrySimulationOutput *sim,
|
||||
int from_index,
|
||||
int to_index);
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -0,0 +1,285 @@
|
|||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* Some nodes have a dynamic number of sockets (e.g. simulation input/output). These nodes store an
|
||||
* array of items in their `bNode->storage` (e.g. `NodeSimulationItem`). Different nodes have
|
||||
* slightly different storage requirements, but a lot of the logic is still the same between nodes.
|
||||
* This file implements various shared functionality that can be used by different nodes to deal
|
||||
* with these item arrays.
|
||||
*
|
||||
* In order to use the functions, one has to implement an "accessor" which tells the shared code
|
||||
* how to deal with specific item arrays. Different functions have different requirements for the
|
||||
* accessor. It's easiest to just look at existing accessors like #SimulationItemsAccessor and
|
||||
* #RepeatItemsAccessor and to implement the same methods.
|
||||
*/
|
||||
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_string_utils.h"
|
||||
|
||||
#include "BKE_node.h"
|
||||
#include "BKE_node_runtime.hh"
|
||||
|
||||
#include "NOD_socket.hh"
|
||||
|
||||
namespace blender::nodes::socket_items {
|
||||
|
||||
/**
|
||||
* References a "C-Array" that is stored elsewhere. This is different from a MutableSpan, because
|
||||
* one can even resize the array through this reference.
|
||||
*/
|
||||
template<typename T> struct SocketItemsRef {
|
||||
T **items;
|
||||
int *items_num;
|
||||
int *active_index;
|
||||
};
|
||||
|
||||
/**
|
||||
* Iterates over the node tree to find the node that this item belongs to.
|
||||
*/
|
||||
template<typename Accessor>
|
||||
inline bNode *find_node_by_item(bNodeTree &ntree, const typename Accessor::ItemT &item)
|
||||
{
|
||||
ntree.ensure_topology_cache();
|
||||
for (bNode *node : ntree.nodes_by_type(Accessor::node_idname)) {
|
||||
SocketItemsRef array = Accessor::get_items_from_node(*node);
|
||||
if (&item >= *array.items && &item < *array.items + *array.items_num) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Low level utility to remove an item from the array and to shift the elements after it.
|
||||
*/
|
||||
template<typename T>
|
||||
inline void remove_item(T **items,
|
||||
int *items_num,
|
||||
int *active_index,
|
||||
const int remove_index,
|
||||
void (*destruct_item)(T *))
|
||||
{
|
||||
static_assert(std::is_trivial_v<T>);
|
||||
BLI_assert(remove_index >= 0);
|
||||
BLI_assert(remove_index < *items_num);
|
||||
|
||||
const int old_items_num = *items_num;
|
||||
const int new_items_num = old_items_num - 1;
|
||||
const int old_active_index = *active_index;
|
||||
|
||||
T *old_items = *items;
|
||||
T *new_items = MEM_cnew_array<T>(new_items_num, __func__);
|
||||
|
||||
std::copy_n(old_items, remove_index, new_items);
|
||||
std::copy_n(
|
||||
old_items + remove_index + 1, old_items_num - remove_index - 1, new_items + remove_index);
|
||||
|
||||
destruct_item(&old_items[remove_index]);
|
||||
MEM_SAFE_FREE(old_items);
|
||||
|
||||
const int new_active_index = std::max(
|
||||
0, old_active_index == new_items_num ? new_items_num - 1 : old_active_index);
|
||||
|
||||
*items = new_items;
|
||||
*items_num = new_items_num;
|
||||
*active_index = new_active_index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Low level utility to remove all elements from an items array.
|
||||
*/
|
||||
template<typename T>
|
||||
inline void clear_items(T **items, int *items_num, int *active_index, void (*destruct_item)(T *))
|
||||
{
|
||||
static_assert(std::is_trivial_v<T>);
|
||||
for (const int i : blender::IndexRange(*items_num)) {
|
||||
destruct_item(&(*items)[i]);
|
||||
}
|
||||
MEM_SAFE_FREE(*items);
|
||||
*items_num = 0;
|
||||
*active_index = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Low level utility to move one item from one index to another.
|
||||
*/
|
||||
template<typename T>
|
||||
inline void move_item(T *items, const int items_num, const int from_index, const int to_index)
|
||||
{
|
||||
static_assert(std::is_trivial_v<T>);
|
||||
BLI_assert(from_index >= 0);
|
||||
BLI_assert(from_index < items_num);
|
||||
BLI_assert(to_index >= 0);
|
||||
BLI_assert(to_index < items_num);
|
||||
UNUSED_VARS_NDEBUG(items_num);
|
||||
|
||||
if (from_index == to_index) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (from_index < to_index) {
|
||||
const T tmp = items[from_index];
|
||||
for (int i = from_index; i < to_index; i++) {
|
||||
items[i] = items[i + 1];
|
||||
}
|
||||
items[to_index] = tmp;
|
||||
}
|
||||
else if (from_index > to_index) {
|
||||
const T tmp = items[from_index];
|
||||
for (int i = from_index; i > to_index; i--) {
|
||||
items[i] = items[i - 1];
|
||||
}
|
||||
items[to_index] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the name of an existing item and makes sure that the name is unique among other the
|
||||
* other items in the same array.
|
||||
*/
|
||||
template<typename Accessor>
|
||||
inline void set_item_name_and_make_unique(bNode &node,
|
||||
typename Accessor::ItemT &item,
|
||||
const char *value)
|
||||
{
|
||||
using ItemT = typename Accessor::ItemT;
|
||||
SocketItemsRef array = Accessor::get_items_from_node(node);
|
||||
const char *default_name = nodeStaticSocketLabel(*Accessor::get_socket_type(item), 0);
|
||||
|
||||
char unique_name[MAX_NAME + 4];
|
||||
STRNCPY(unique_name, value);
|
||||
|
||||
struct Args {
|
||||
SocketItemsRef<ItemT> array;
|
||||
ItemT *item;
|
||||
} args = {array, &item};
|
||||
BLI_uniquename_cb(
|
||||
[](void *arg, const char *name) {
|
||||
const Args &args = *static_cast<Args *>(arg);
|
||||
for (ItemT &item : blender::MutableSpan(*args.array.items, *args.array.items_num)) {
|
||||
if (&item != args.item) {
|
||||
if (STREQ(*Accessor::get_name(item), name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
&args,
|
||||
default_name,
|
||||
'.',
|
||||
unique_name,
|
||||
ARRAY_SIZE(unique_name));
|
||||
|
||||
char **item_name = Accessor::get_name(item);
|
||||
MEM_SAFE_FREE(*item_name);
|
||||
*item_name = BLI_strdup(unique_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new item at the end with the given socket type and name.
|
||||
*/
|
||||
template<typename Accessor>
|
||||
inline typename Accessor::ItemT *add_item_with_socket_and_name(
|
||||
bNode &node, const eNodeSocketDatatype socket_type, const char *name)
|
||||
{
|
||||
using ItemT = typename Accessor::ItemT;
|
||||
BLI_assert(Accessor::supports_socket_type(socket_type));
|
||||
|
||||
SocketItemsRef array = Accessor::get_items_from_node(node);
|
||||
|
||||
ItemT *old_items = *array.items;
|
||||
const int old_items_num = *array.items_num;
|
||||
const int new_items_num = old_items_num + 1;
|
||||
|
||||
ItemT *new_items = MEM_cnew_array<ItemT>(new_items_num, __func__);
|
||||
std::copy_n(old_items, old_items_num, new_items);
|
||||
ItemT &new_item = new_items[old_items_num];
|
||||
|
||||
Accessor::init_with_socket_type_and_name(node, new_item, socket_type, name);
|
||||
|
||||
MEM_SAFE_FREE(old_items);
|
||||
*array.items = new_items;
|
||||
*array.items_num = new_items_num;
|
||||
*array.active_index = old_items_num;
|
||||
|
||||
return &new_item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the link connects to the `extend_socket`. If yes, create a new item for the linked
|
||||
JacquesLucke marked this conversation as resolved
Outdated
Hans Goudey
commented
`the links connects` -> `the link connects`
|
||||
* socket, update the node and then change the link to point to the new socket.
|
||||
* \return False if the link should be removed.
|
||||
*/
|
||||
template<typename Accessor>
|
||||
[[nodiscard]] inline bool try_add_item_via_extend_socket(bNodeTree &ntree,
|
||||
bNode &extend_node,
|
||||
bNodeSocket &extend_socket,
|
||||
bNode &storage_node,
|
||||
bNodeLink &link)
|
||||
{
|
||||
using ItemT = typename Accessor::ItemT;
|
||||
bNodeSocket *src_socket = nullptr;
|
||||
if (link.tosock == &extend_socket) {
|
||||
src_socket = link.fromsock;
|
||||
}
|
||||
else if (link.fromsock == &extend_socket) {
|
||||
src_socket = link.tosock;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
const eNodeSocketDatatype socket_type = eNodeSocketDatatype(src_socket->type);
|
||||
if (!Accessor::supports_socket_type(socket_type)) {
|
||||
return false;
|
||||
}
|
||||
const ItemT *item = add_item_with_socket_and_name<Accessor>(
|
||||
storage_node, socket_type, src_socket->name);
|
||||
if (item == nullptr) {
|
||||
return false;
|
||||
}
|
||||
update_node_declaration_and_sockets(ntree, extend_node);
|
||||
const std::string item_identifier = Accessor::socket_identifier_for_item(*item);
|
||||
if (extend_socket.is_input()) {
|
||||
bNodeSocket *new_socket = nodeFindSocket(&extend_node, SOCK_IN, item_identifier.c_str());
|
||||
link.tosock = new_socket;
|
||||
}
|
||||
else {
|
||||
bNodeSocket *new_socket = nodeFindSocket(&extend_node, SOCK_OUT, item_identifier.c_str());
|
||||
link.fromsock = new_socket;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow the item array to be extended from any extend-socket in the node.
|
||||
* \return False if the link should be removed.
|
||||
*/
|
||||
template<typename Accessor>
|
||||
[[nodiscard]] inline bool try_add_item_via_any_extend_socket(bNodeTree &ntree,
|
||||
bNode &extend_node,
|
||||
bNode &storage_node,
|
||||
bNodeLink &link)
|
||||
{
|
||||
bNodeSocket *possible_extend_socket = nullptr;
|
||||
if (link.fromnode == &extend_node) {
|
||||
possible_extend_socket = link.fromsock;
|
||||
}
|
||||
if (link.tonode == &extend_node) {
|
||||
possible_extend_socket = link.tosock;
|
||||
}
|
||||
if (possible_extend_socket == nullptr) {
|
||||
return true;
|
||||
}
|
||||
if (!STREQ(possible_extend_socket->idname, "NodeSocketVirtual")) {
|
||||
return true;
|
||||
}
|
||||
return try_add_item_via_extend_socket<Accessor>(
|
||||
ntree, extend_node, *possible_extend_socket, storage_node, link);
|
||||
}
|
||||
|
||||
} // namespace blender::nodes::socket_items
|
|
@ -0,0 +1,127 @@
|
|||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "DNA_node_types.h"
|
||||
|
||||
#include "NOD_socket_items.hh"
|
||||
|
||||
namespace blender::nodes {
|
||||
|
||||
/**
|
||||
* Makes it possible to use various functions (e.g. the ones in `NOD_socket_items.hh`) with
|
||||
* simulation items.
|
||||
*/
|
||||
struct SimulationItemsAccessor {
|
||||
using ItemT = NodeSimulationItem;
|
||||
static StructRNA *item_srna;
|
||||
static int node_type;
|
||||
static constexpr const char *node_idname = "GeometryNodeSimulationOutput";
|
||||
|
||||
static socket_items::SocketItemsRef<NodeSimulationItem> get_items_from_node(bNode &node)
|
||||
{
|
||||
auto *storage = static_cast<NodeGeometrySimulationOutput *>(node.storage);
|
||||
return {&storage->items, &storage->items_num, &storage->active_index};
|
||||
}
|
||||
static void destruct_item(NodeSimulationItem *item)
|
||||
{
|
||||
MEM_SAFE_FREE(item->name);
|
||||
}
|
||||
static short *get_socket_type(NodeSimulationItem &item)
|
||||
{
|
||||
return &item.socket_type;
|
||||
}
|
||||
static char **get_name(NodeSimulationItem &item)
|
||||
{
|
||||
return &item.name;
|
||||
}
|
||||
static bool supports_socket_type(const eNodeSocketDatatype socket_type)
|
||||
{
|
||||
return ELEM(socket_type,
|
||||
SOCK_FLOAT,
|
||||
SOCK_VECTOR,
|
||||
SOCK_RGBA,
|
||||
SOCK_BOOLEAN,
|
||||
SOCK_ROTATION,
|
||||
SOCK_INT,
|
||||
SOCK_STRING,
|
||||
SOCK_GEOMETRY);
|
||||
}
|
||||
static void init_with_socket_type_and_name(bNode &node,
|
||||
NodeSimulationItem &item,
|
||||
const eNodeSocketDatatype socket_type,
|
||||
const char *name)
|
||||
{
|
||||
auto *storage = static_cast<NodeGeometrySimulationOutput *>(node.storage);
|
||||
item.socket_type = socket_type;
|
||||
item.identifier = storage->next_identifier++;
|
||||
socket_items::set_item_name_and_make_unique<SimulationItemsAccessor>(node, item, name);
|
||||
}
|
||||
static std::string socket_identifier_for_item(const NodeSimulationItem &item)
|
||||
{
|
||||
return "Item_" + std::to_string(item.identifier);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Makes it possible to use various functions (e.g. the ones in `NOD_socket_items.hh`) with
|
||||
* repeat items.
|
||||
*/
|
||||
struct RepeatItemsAccessor {
|
||||
using ItemT = NodeRepeatItem;
|
||||
static StructRNA *item_srna;
|
||||
static int node_type;
|
||||
static constexpr const char *node_idname = "GeometryNodeRepeatOutput";
|
||||
|
||||
static socket_items::SocketItemsRef<NodeRepeatItem> get_items_from_node(bNode &node)
|
||||
{
|
||||
auto *storage = static_cast<NodeGeometryRepeatOutput *>(node.storage);
|
||||
return {&storage->items, &storage->items_num, &storage->active_index};
|
||||
}
|
||||
static void destruct_item(NodeRepeatItem *item)
|
||||
{
|
||||
MEM_SAFE_FREE(item->name);
|
||||
}
|
||||
static short *get_socket_type(NodeRepeatItem &item)
|
||||
{
|
||||
return &item.socket_type;
|
||||
}
|
||||
static char **get_name(NodeRepeatItem &item)
|
||||
{
|
||||
return &item.name;
|
||||
}
|
||||
static bool supports_socket_type(const eNodeSocketDatatype socket_type)
|
||||
{
|
||||
return ELEM(socket_type,
|
||||
SOCK_FLOAT,
|
||||
SOCK_VECTOR,
|
||||
SOCK_RGBA,
|
||||
SOCK_BOOLEAN,
|
||||
SOCK_ROTATION,
|
||||
SOCK_INT,
|
||||
SOCK_STRING,
|
||||
SOCK_GEOMETRY,
|
||||
SOCK_OBJECT,
|
||||
SOCK_MATERIAL,
|
||||
SOCK_IMAGE,
|
||||
SOCK_COLLECTION);
|
||||
}
|
||||
static void init_with_socket_type_and_name(bNode &node,
|
||||
NodeRepeatItem &item,
|
||||
const eNodeSocketDatatype socket_type,
|
||||
const char *name)
|
||||
{
|
||||
auto *storage = static_cast<NodeGeometryRepeatOutput *>(node.storage);
|
||||
item.socket_type = socket_type;
|
||||
item.identifier = storage->next_identifier++;
|
||||
socket_items::set_item_name_and_make_unique<RepeatItemsAccessor>(node, item, name);
|
||||
}
|
||||
static std::string socket_identifier_for_item(const NodeRepeatItem &item)
|
||||
{
|
||||
return "Item_" + std::to_string(item.identifier);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace blender::nodes
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include "NOD_geometry.hh"
|
||||
#include "NOD_socket.hh"
|
||||
#include "NOD_zone_socket_items.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
|
@ -45,40 +46,12 @@ static void node_init(bNodeTree * /*tree*/, bNode *node)
|
|||
|
||||
static bool node_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
|
||||
{
|
||||
const bNode *output_node = ntree->node_by_id(node_storage(*node).output_node_id);
|
||||
bNode *output_node = ntree->node_by_id(node_storage(*node).output_node_id);
|
||||
if (!output_node) {
|
||||
return true;
|
||||
}
|
||||
auto &storage = *static_cast<NodeGeometryRepeatOutput *>(output_node->storage);
|
||||
if (link->tonode == node) {
|
||||
if (link->tosock->identifier == StringRef("__extend__")) {
|
||||
if (const NodeRepeatItem *item = storage.add_item(link->fromsock->name,
|
||||
eNodeSocketDatatype(link->fromsock->type)))
|
||||
{
|
||||
update_node_declaration_and_sockets(*ntree, *node);
|
||||
link->tosock = nodeFindSocket(node, SOCK_IN, item->identifier_str().c_str());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (link->fromnode == node) {
|
||||
if (link->fromsock->identifier == StringRef("__extend__")) {
|
||||
if (const NodeRepeatItem *item = storage.add_item(link->tosock->name,
|
||||
eNodeSocketDatatype(link->tosock->type)))
|
||||
{
|
||||
update_node_declaration_and_sockets(*ntree, *node);
|
||||
link->fromsock = nodeFindSocket(node, SOCK_OUT, item->identifier_str().c_str());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return socket_items::try_add_item_via_any_extend_socket<RepeatItemsAccessor>(
|
||||
*ntree, *node, *output_node, *link);
|
||||
}
|
||||
|
||||
static void node_register()
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include "NOD_geometry.hh"
|
||||
#include "NOD_socket.hh"
|
||||
#include "NOD_zone_socket_items.hh"
|
||||
|
||||
#include "BLI_string_utils.h"
|
||||
|
||||
|
@ -87,7 +88,7 @@ static std::unique_ptr<SocketDeclaration> socket_declaration_for_repeat_item(
|
|||
}
|
||||
|
||||
decl->name = item.name ? item.name : "";
|
||||
decl->identifier = item.identifier_str();
|
||||
decl->identifier = RepeatItemsAccessor::socket_identifier_for_item(item);
|
||||
decl->in_out = in_out;
|
||||
return decl;
|
||||
}
|
||||
|
@ -175,36 +176,8 @@ static void node_copy_storage(bNodeTree * /*dst_tree*/, bNode *dst_node, const b
|
|||
|
||||
static bool node_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
|
||||
{
|
||||
NodeGeometryRepeatOutput &storage = node_storage(*node);
|
||||
if (link->tonode == node) {
|
||||
if (link->tosock->identifier == StringRef("__extend__")) {
|
||||
if (const NodeRepeatItem *item = storage.add_item(link->fromsock->name,
|
||||
eNodeSocketDatatype(link->fromsock->type)))
|
||||
{
|
||||
update_node_declaration_and_sockets(*ntree, *node);
|
||||
link->tosock = nodeFindSocket(node, SOCK_IN, item->identifier_str().c_str());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (link->fromnode == node) {
|
||||
if (link->fromsock->identifier == StringRef("__extend__")) {
|
||||
if (const NodeRepeatItem *item = storage.add_item(link->tosock->name,
|
||||
eNodeSocketDatatype(link->tosock->type)))
|
||||
{
|
||||
update_node_declaration_and_sockets(*ntree, *node);
|
||||
link->fromsock = nodeFindSocket(node, SOCK_OUT, item->identifier_str().c_str());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return socket_items::try_add_item_via_any_extend_socket<RepeatItemsAccessor>(
|
||||
*ntree, *node, *node, *link);
|
||||
}
|
||||
|
||||
static void node_register()
|
||||
|
@ -230,83 +203,3 @@ blender::MutableSpan<NodeRepeatItem> NodeGeometryRepeatOutput::items_span()
|
|||
{
|
||||
return blender::MutableSpan<NodeRepeatItem>(items, items_num);
|
||||
}
|
||||
|
||||
bool NodeRepeatItem::supports_type(const eNodeSocketDatatype type)
|
||||
{
|
||||
return ELEM(type,
|
||||
SOCK_FLOAT,
|
||||
SOCK_VECTOR,
|
||||
SOCK_RGBA,
|
||||
SOCK_BOOLEAN,
|
||||
SOCK_ROTATION,
|
||||
SOCK_INT,
|
||||
SOCK_STRING,
|
||||
SOCK_GEOMETRY,
|
||||
SOCK_OBJECT,
|
||||
SOCK_MATERIAL,
|
||||
SOCK_IMAGE,
|
||||
SOCK_COLLECTION);
|
||||
}
|
||||
|
||||
std::string NodeRepeatItem::identifier_str() const
|
||||
{
|
||||
return "Item_" + std::to_string(this->identifier);
|
||||
}
|
||||
|
||||
NodeRepeatItem *NodeGeometryRepeatOutput::add_item(const char *name,
|
||||
const eNodeSocketDatatype type)
|
||||
{
|
||||
if (!NodeRepeatItem::supports_type(type)) {
|
||||
return nullptr;
|
||||
}
|
||||
const int insert_index = this->items_num;
|
||||
NodeRepeatItem *old_items = this->items;
|
||||
|
||||
this->items = MEM_cnew_array<NodeRepeatItem>(this->items_num + 1, __func__);
|
||||
std::copy_n(old_items, insert_index, this->items);
|
||||
NodeRepeatItem &new_item = this->items[insert_index];
|
||||
std::copy_n(old_items + insert_index + 1,
|
||||
this->items_num - insert_index,
|
||||
this->items + insert_index + 1);
|
||||
|
||||
new_item.identifier = this->next_identifier++;
|
||||
this->set_item_name(new_item, name);
|
||||
new_item.socket_type = type;
|
||||
|
||||
this->items_num++;
|
||||
MEM_SAFE_FREE(old_items);
|
||||
return &new_item;
|
||||
}
|
||||
|
||||
void NodeGeometryRepeatOutput::set_item_name(NodeRepeatItem &item, const char *name)
|
||||
{
|
||||
char unique_name[MAX_NAME + 4];
|
||||
STRNCPY(unique_name, name);
|
||||
|
||||
struct Args {
|
||||
NodeGeometryRepeatOutput *storage;
|
||||
const NodeRepeatItem *item;
|
||||
} args = {this, &item};
|
||||
|
||||
const char *default_name = nodeStaticSocketLabel(item.socket_type, 0);
|
||||
BLI_uniquename_cb(
|
||||
[](void *arg, const char *name) {
|
||||
const Args &args = *static_cast<Args *>(arg);
|
||||
for (const NodeRepeatItem &item : args.storage->items_span()) {
|
||||
if (&item != args.item) {
|
||||
if (STREQ(item.name, name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
&args,
|
||||
default_name,
|
||||
'.',
|
||||
unique_name,
|
||||
ARRAY_SIZE(unique_name));
|
||||
|
||||
MEM_SAFE_FREE(item.name);
|
||||
item.name = BLI_strdup(unique_name);
|
||||
}
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
|
||||
#include "NOD_geometry.hh"
|
||||
#include "NOD_socket.hh"
|
||||
#include "NOD_socket_items.hh"
|
||||
#include "NOD_zone_socket_items.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
|
@ -211,44 +213,12 @@ static void node_init(bNodeTree * /*tree*/, bNode *node)
|
|||
|
||||
static bool node_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
|
||||
{
|
||||
const bNode *output_node = ntree->node_by_id(node_storage(*node).output_node_id);
|
||||
bNode *output_node = ntree->node_by_id(node_storage(*node).output_node_id);
|
||||
if (!output_node) {
|
||||
return true;
|
||||
}
|
||||
|
||||
NodeGeometrySimulationOutput &storage = *static_cast<NodeGeometrySimulationOutput *>(
|
||||
output_node->storage);
|
||||
|
||||
if (link->tonode == node) {
|
||||
if (link->tosock->identifier == StringRef("__extend__")) {
|
||||
if (const NodeSimulationItem *item = NOD_geometry_simulation_output_add_item_from_socket(
|
||||
&storage, link->fromnode, link->fromsock))
|
||||
{
|
||||
update_node_declaration_and_sockets(*ntree, *node);
|
||||
link->tosock = nodeFindSocket(
|
||||
node, SOCK_IN, socket_identifier_for_simulation_item(*item).c_str());
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
BLI_assert(link->fromnode == node);
|
||||
if (link->fromsock->identifier == StringRef("__extend__")) {
|
||||
if (const NodeSimulationItem *item = NOD_geometry_simulation_output_add_item_from_socket(
|
||||
&storage, link->tonode, link->tosock))
|
||||
{
|
||||
update_node_declaration_and_sockets(*ntree, *node);
|
||||
link->fromsock = nodeFindSocket(
|
||||
node, SOCK_OUT, socket_identifier_for_simulation_item(*item).c_str());
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return socket_items::try_add_item_via_any_extend_socket<SimulationItemsAccessor>(
|
||||
*ntree, *node, *output_node, *link);
|
||||
}
|
||||
|
||||
static void node_register()
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "NOD_common.h"
|
||||
#include "NOD_geometry.hh"
|
||||
#include "NOD_socket.hh"
|
||||
#include "NOD_zone_socket_items.hh"
|
||||
|
||||
#include "FN_field_cpp_type.hh"
|
||||
|
||||
|
@ -51,7 +52,7 @@ namespace blender::nodes {
|
|||
|
||||
std::string socket_identifier_for_simulation_item(const NodeSimulationItem &item)
|
||||
{
|
||||
return "Item_" + std::to_string(item.identifier);
|
||||
return SimulationItemsAccessor::socket_identifier_for_item(item);
|
||||
}
|
||||
|
||||
static std::unique_ptr<SocketDeclaration> socket_declaration_for_simulation_item(
|
||||
|
@ -60,7 +61,7 @@ static std::unique_ptr<SocketDeclaration> socket_declaration_for_simulation_item
|
|||
const int corresponding_input = -1)
|
||||
{
|
||||
const eNodeSocketDatatype socket_type = eNodeSocketDatatype(item.socket_type);
|
||||
BLI_assert(NOD_geometry_simulation_output_item_socket_type_supported(socket_type));
|
||||
BLI_assert(SimulationItemsAccessor::supports_socket_type(socket_type));
|
||||
|
||||
std::unique_ptr<SocketDeclaration> decl;
|
||||
switch (socket_type) {
|
||||
|
@ -138,28 +139,6 @@ void socket_declarations_for_simulation_items(const Span<NodeSimulationItem> ite
|
|||
r_declaration.items.append(std::move(output_extend_decl));
|
||||
}
|
||||
|
||||
struct SimulationItemsUniqueNameArgs {
|
||||
NodeGeometrySimulationOutput *sim;
|
||||
const NodeSimulationItem *item;
|
||||
};
|
||||
|
||||
static bool simulation_items_unique_name_check(void *arg, const char *name)
|
||||
{
|
||||
const SimulationItemsUniqueNameArgs &args = *static_cast<const SimulationItemsUniqueNameArgs *>(
|
||||
arg);
|
||||
for (const NodeSimulationItem &item : args.sim->items_span()) {
|
||||
if (&item != args.item) {
|
||||
if (STREQ(item.name, name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (STREQ(name, "Delta Time")) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const CPPType &get_simulation_item_cpp_type(const eNodeSocketDatatype socket_type)
|
||||
{
|
||||
const char *socket_idname = nodeStaticSocketType(socket_type, 0);
|
||||
|
@ -988,37 +967,8 @@ static void node_layout_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
|
|||
|
||||
static bool node_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
|
||||
{
|
||||
NodeGeometrySimulationOutput &storage = node_storage(*node);
|
||||
if (link->tonode == node) {
|
||||
if (link->tosock->identifier == StringRef("__extend__")) {
|
||||
if (const NodeSimulationItem *item = NOD_geometry_simulation_output_add_item_from_socket(
|
||||
&storage, link->fromnode, link->fromsock))
|
||||
{
|
||||
update_node_declaration_and_sockets(*ntree, *node);
|
||||
link->tosock = nodeFindSocket(
|
||||
node, SOCK_IN, socket_identifier_for_simulation_item(*item).c_str());
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
BLI_assert(link->fromnode == node);
|
||||
if (link->fromsock->identifier == StringRef("__extend__")) {
|
||||
if (const NodeSimulationItem *item = NOD_geometry_simulation_output_add_item_from_socket(
|
||||
&storage, link->fromnode, link->tosock))
|
||||
{
|
||||
update_node_declaration_and_sockets(*ntree, *node);
|
||||
link->fromsock = nodeFindSocket(
|
||||
node, SOCK_OUT, socket_identifier_for_simulation_item(*item).c_str());
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return socket_items::try_add_item_via_any_extend_socket<SimulationItemsAccessor>(
|
||||
*ntree, *node, *node, *link);
|
||||
}
|
||||
|
||||
static void node_register()
|
||||
|
@ -1048,203 +998,3 @@ blender::MutableSpan<NodeSimulationItem> NodeGeometrySimulationOutput::items_spa
|
|||
{
|
||||
return blender::MutableSpan<NodeSimulationItem>(items, items_num);
|
||||
}
|
||||
|
||||
blender::IndexRange NodeGeometrySimulationOutput::items_range() const
|
||||
{
|
||||
return blender::IndexRange(items_num);
|
||||
}
|
||||
|
||||
bool NOD_geometry_simulation_output_item_socket_type_supported(
|
||||
const eNodeSocketDatatype socket_type)
|
||||
{
|
||||
return ELEM(socket_type,
|
||||
SOCK_FLOAT,
|
||||
SOCK_VECTOR,
|
||||
SOCK_RGBA,
|
||||
SOCK_BOOLEAN,
|
||||
SOCK_ROTATION,
|
||||
SOCK_INT,
|
||||
SOCK_STRING,
|
||||
SOCK_GEOMETRY);
|
||||
}
|
||||
|
||||
bNode *NOD_geometry_simulation_output_find_node_by_item(bNodeTree *ntree,
|
||||
const NodeSimulationItem *item)
|
||||
{
|
||||
ntree->ensure_topology_cache();
|
||||
for (bNode *node : ntree->nodes_by_type("GeometryNodeSimulationOutput")) {
|
||||
NodeGeometrySimulationOutput *sim = static_cast<NodeGeometrySimulationOutput *>(node->storage);
|
||||
if (sim->items_span().contains_ptr(item)) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool NOD_geometry_simulation_output_item_set_unique_name(NodeGeometrySimulationOutput *sim,
|
||||
NodeSimulationItem *item,
|
||||
const char *name,
|
||||
const char *defname)
|
||||
{
|
||||
char unique_name[MAX_NAME + 4];
|
||||
STRNCPY(unique_name, name);
|
||||
|
||||
blender::nodes::SimulationItemsUniqueNameArgs args{sim, item};
|
||||
const bool name_changed = BLI_uniquename_cb(blender::nodes::simulation_items_unique_name_check,
|
||||
&args,
|
||||
defname,
|
||||
'.',
|
||||
unique_name,
|
||||
ARRAY_SIZE(unique_name));
|
||||
MEM_delete(item->name);
|
||||
item->name = BLI_strdup(unique_name);
|
||||
return name_changed;
|
||||
}
|
||||
|
||||
bool NOD_geometry_simulation_output_contains_item(NodeGeometrySimulationOutput *sim,
|
||||
const NodeSimulationItem *item)
|
||||
{
|
||||
return sim->items_span().contains_ptr(item);
|
||||
}
|
||||
|
||||
NodeSimulationItem *NOD_geometry_simulation_output_get_active_item(
|
||||
NodeGeometrySimulationOutput *sim)
|
||||
{
|
||||
if (!sim->items_range().contains(sim->active_index)) {
|
||||
return nullptr;
|
||||
}
|
||||
return &sim->items[sim->active_index];
|
||||
}
|
||||
|
||||
void NOD_geometry_simulation_output_set_active_item(NodeGeometrySimulationOutput *sim,
|
||||
NodeSimulationItem *item)
|
||||
{
|
||||
if (sim->items_span().contains_ptr(item)) {
|
||||
sim->active_index = item - sim->items;
|
||||
}
|
||||
}
|
||||
|
||||
NodeSimulationItem *NOD_geometry_simulation_output_find_item(NodeGeometrySimulationOutput *sim,
|
||||
const char *name)
|
||||
{
|
||||
for (NodeSimulationItem &item : sim->items_span()) {
|
||||
if (STREQ(item.name, name)) {
|
||||
return &item;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NodeSimulationItem *NOD_geometry_simulation_output_add_item(NodeGeometrySimulationOutput *sim,
|
||||
const short socket_type,
|
||||
const char *name)
|
||||
{
|
||||
return NOD_geometry_simulation_output_insert_item(sim, socket_type, name, sim->items_num);
|
||||
}
|
||||
|
||||
NodeSimulationItem *NOD_geometry_simulation_output_insert_item(NodeGeometrySimulationOutput *sim,
|
||||
const short socket_type,
|
||||
const char *name,
|
||||
int index)
|
||||
{
|
||||
if (!NOD_geometry_simulation_output_item_socket_type_supported(eNodeSocketDatatype(socket_type)))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NodeSimulationItem *old_items = sim->items;
|
||||
sim->items = MEM_cnew_array<NodeSimulationItem>(sim->items_num + 1, __func__);
|
||||
for (const int i : blender::IndexRange(index)) {
|
||||
sim->items[i] = old_items[i];
|
||||
}
|
||||
for (const int i : blender::IndexRange(index, sim->items_num - index)) {
|
||||
sim->items[i + 1] = old_items[i];
|
||||
}
|
||||
|
||||
const char *defname = nodeStaticSocketLabel(socket_type, 0);
|
||||
NodeSimulationItem &added_item = sim->items[index];
|
||||
added_item.identifier = sim->next_identifier++;
|
||||
NOD_geometry_simulation_output_item_set_unique_name(sim, &added_item, name, defname);
|
||||
added_item.socket_type = socket_type;
|
||||
|
||||
sim->items_num++;
|
||||
MEM_SAFE_FREE(old_items);
|
||||
|
||||
return &added_item;
|
||||
}
|
||||
|
||||
NodeSimulationItem *NOD_geometry_simulation_output_add_item_from_socket(
|
||||
NodeGeometrySimulationOutput *sim, const bNode * /*from_node*/, const bNodeSocket *from_sock)
|
||||
{
|
||||
return NOD_geometry_simulation_output_insert_item(
|
||||
sim, from_sock->type, from_sock->name, sim->items_num);
|
||||
}
|
||||
|
||||
NodeSimulationItem *NOD_geometry_simulation_output_insert_item_from_socket(
|
||||
NodeGeometrySimulationOutput *sim,
|
||||
const bNode * /*from_node*/,
|
||||
const bNodeSocket *from_sock,
|
||||
int index)
|
||||
{
|
||||
return NOD_geometry_simulation_output_insert_item(sim, from_sock->type, from_sock->name, index);
|
||||
}
|
||||
|
||||
void NOD_geometry_simulation_output_remove_item(NodeGeometrySimulationOutput *sim,
|
||||
NodeSimulationItem *item)
|
||||
{
|
||||
const int index = item - sim->items;
|
||||
if (index < 0 || index >= sim->items_num) {
|
||||
return;
|
||||
}
|
||||
|
||||
NodeSimulationItem *old_items = sim->items;
|
||||
sim->items = MEM_cnew_array<NodeSimulationItem>(sim->items_num - 1, __func__);
|
||||
for (const int i : blender::IndexRange(index)) {
|
||||
sim->items[i] = old_items[i];
|
||||
}
|
||||
for (const int i : blender::IndexRange(index, sim->items_num - index).drop_front(1)) {
|
||||
sim->items[i - 1] = old_items[i];
|
||||
}
|
||||
|
||||
MEM_SAFE_FREE(old_items[index].name);
|
||||
|
||||
sim->items_num--;
|
||||
MEM_SAFE_FREE(old_items);
|
||||
}
|
||||
|
||||
void NOD_geometry_simulation_output_clear_items(NodeGeometrySimulationOutput *sim)
|
||||
{
|
||||
for (NodeSimulationItem &item : sim->items_span()) {
|
||||
MEM_SAFE_FREE(item.name);
|
||||
}
|
||||
MEM_SAFE_FREE(sim->items);
|
||||
sim->items = nullptr;
|
||||
sim->items_num = 0;
|
||||
}
|
||||
|
||||
void NOD_geometry_simulation_output_move_item(NodeGeometrySimulationOutput *sim,
|
||||
int from_index,
|
||||
int to_index)
|
||||
{
|
||||
BLI_assert(from_index >= 0 && from_index < sim->items_num);
|
||||
BLI_assert(to_index >= 0 && to_index < sim->items_num);
|
||||
|
||||
if (from_index == to_index) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (from_index < to_index) {
|
||||
const NodeSimulationItem tmp = sim->items[from_index];
|
||||
for (int i = from_index; i < to_index; ++i) {
|
||||
sim->items[i] = sim->items[i + 1];
|
||||
}
|
||||
sim->items[to_index] = tmp;
|
||||
}
|
||||
else /* from_index > to_index */ {
|
||||
const NodeSimulationItem tmp = sim->items[from_index];
|
||||
for (int i = from_index; i > to_index; --i) {
|
||||
sim->items[i] = sim->items[i - 1];
|
||||
}
|
||||
sim->items[to_index] = tmp;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "RNA_prototypes.h"
|
||||
|
||||
#include "NOD_zone_socket_items.hh"
|
||||
|
||||
#include "BKE_node.hh"
|
||||
|
||||
namespace blender::nodes {
|
||||
|
||||
/* Defined here to avoid including the relevant headers in the header. */
|
||||
|
||||
JacquesLucke marked this conversation as resolved
Outdated
Hans Goudey
commented
I guess this one is to avoid including I guess this one is to avoid including `BKE_node.hh` in `NOD_zone_socket_items.hh`? Seems reasonable, maybe worth a comment though?
|
||||
StructRNA *SimulationItemsAccessor::item_srna = &RNA_SimulationStateItem;
|
||||
int SimulationItemsAccessor::node_type = GEO_NODE_SIMULATION_OUTPUT;
|
||||
|
||||
StructRNA *RepeatItemsAccessor::item_srna = &RNA_RepeatItem;
|
||||
int RepeatItemsAccessor::node_type = GEO_NODE_REPEAT_OUTPUT;
|
||||
|
||||
} // namespace blender::nodes
|
Loading…
Reference in New Issue
a item
->an item