Geometry Nodes: deduplicate code to deal with dynamic socket amounts
The goal of this refactor is to reduce the amount of boilerplate code that is necessary to have a dynamic number of sockets on nodes. This is achieved by making the code more reusable. Currently, only the simulation and repeat zone nodes make use of this. However, even with just those two, the amount of code is reduced already. The benefit of this refactor will become even more significant as more nodes support a dynamic number of sockets. For example, the bake node and for-each zone will also benefit from this. We could probably make some of the utility functions non-templates using type erasure. This could reduce the compilation overhead when the number of nodes with item arrays increases. The main reason for why everything is templated now is that it made this refactor easier. Without this patch, all the code was essentially "manually templated". So the implementations look still similar to before now, just that concrete types are replaced with template parameters. No user-visible changes are expected. Pull Request: https://projects.blender.org/blender/blender/pulls/113114
This commit is contained in:
@@ -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;
|
||||
|
||||
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);
|
||||
|
||||
/** \} */
|
||||
|
||||
285
source/blender/nodes/NOD_socket_items.hh
Normal file
285
source/blender/nodes/NOD_socket_items.hh
Normal file
@@ -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
|
||||
* 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
|
||||
127
source/blender/nodes/NOD_zone_socket_items.hh
Normal file
127
source/blender/nodes/NOD_zone_socket_items.hh
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
21
source/blender/nodes/intern/node_zone_socket_items.cc
Normal file
21
source/blender/nodes/intern/node_zone_socket_items.cc
Normal file
@@ -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. */
|
||||
|
||||
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
|
||||
Reference in New Issue
Block a user